Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

THIR

THIR(“Typed High-Level Intermediate Representation”)は、以前は “High-Level Abstract IR” の略として HAIR と呼ばれていた、rustc で使われるもう一つの IR であり、 型検査の後に生成されます。これは( 2024年1月時点で) MIR 構築網羅性検査、および unsafe 性検査に使われています。

名前から推測できるかもしれませんが、THIR は HIR を低水準化したバージョンであり、 すべての型が埋められています。これは型検査が完了した後に可能になります。 しかし、THIR には HIR と区別される、他にも興味深い特徴があります。

  • MIR と同様に、THIR はボディ、つまり「実行可能なコード」のみを表します。これには 関数ボディだけでなく、たとえば const 初期化子も含まれます。 具体的には、すべてのボディ所有者について THIR が作成されます。 したがって、THIR には structtrait のようなアイテムを表すものはありません。

  • THIR の各ボディは一時的にのみ保存され、不要になり次第すぐに破棄されます。 これは、コンパイルプロセスの最後まで保存される場合(HIR で行われていること)とは対照的です。

  • THIR では、すべてのノードの型を利用可能にすることに加えて、HIR と比べて追加の 脱糖も行われています。 たとえば、自動的な参照とデリファレンスは 明示化され、メソッド呼び出しとオーバーロードされた演算子は通常の関数呼び出しに変換されます。 破棄スコープも明示化されます。

  • 文、式、match アーム、ブロック、パラメータは別々に保存されます。 たとえば、 stmts 配列内の文は、exprs 配列内の式をそのインデックス(ExprId として表されます)で参照します。

THIR は rustc_mir_build::thir にあります。 thir::Expr を構築するには、 THIR が割り当てられるメモリアリーナを渡して、thir_body 関数を使うことができます。 このアリーナを破棄すると THIR も破棄されます。 これはピークメモリを抑えるのに役立ちます。 クレートのすべてのボディの THIR 表現を同時にメモリ上に保持するのは、非常に重くなります。

rustc-Zunpretty=thir-tree フラグを渡すことで、THIR のデバッグ表現を取得できます。

実例として、次の例を使ってみましょう。

fn main() {
    let x = 1 + 2;
}

これが THIR でどのように表現されるかを以下に示します( 2022年8月時点)。

```rust,no_run
Thir {
    // match アームなし
    arms: [],
    exprs: [
        // 式 0、値 1 のリテラル
        Expr {
            ty: i32,
            temp_lifetime: Some(
                Node(1),
            ),
            span: oneplustwo.rs:2:13: 2:14 (#0),
            kind: Literal {
                lit: Spanned {
                    node: Int(
                        1,
                        Unsuffixed,
                    ),
                    span: oneplustwo.rs:2:13: 2:14 (#0),
                },
                neg: false,
            },
        },
        // 式 1、リテラル 1 を囲むスコープ
        Expr {
            ty: i32,
            temp_lifetime: Some(
                Node(1),
            ),
            span: oneplustwo.rs:2:13: 2:14 (#0),
            kind: Scope {
                // 上記の式 0 への参照
                region_scope: Node(3),
                lint_level: Explicit(
                    HirId {
                        owner: DefId(0:3 ~ oneplustwo[6932]::main),
                        local_id: 3,
                    },
                ),
                value: e0,
            },
        },
        // 式 2、リテラル 2
        Expr {
            ty: i32,
            temp_lifetime: Some(
                Node(1),
            ),
            span: oneplustwo.rs:2:17: 2:18 (#0),
            kind: Literal {
                lit: Spanned {
                    node: Int(
                        2,
                        Unsuffixed,
                    ),
                    span: oneplustwo.rs:2:17: 2:18 (#0),
                },
                neg: false,
            },
        },
        // 式 3、リテラル 2 を囲むスコープ
        Expr {
            ty: i32,
            temp_lifetime: Some(
                Node(1),
            ),
            span: oneplustwo.rs:2:17: 2:18 (#0),
            kind: Scope {
                region_scope: Node(4),
                lint_level: Explicit(
                    HirId {
                        owner: DefId(0:3 ~ oneplustwo[6932]::main),
                        local_id: 4,
                    },
                ),
                // 上記の式 2 への参照
                value: e2,
            },
        },
        // 式 4、1 + 2 を表す
        Expr {
            ty: i32,
            temp_lifetime: Some(
                Node(1),
            ),
            span: oneplustwo.rs:2:13: 2:18 (#0),
            kind: Binary {
                op: Add,
                // 上記のリテラルを囲むスコープへの参照
                lhs: e1,
                rhs: e3,
            },
        },
        // 式 5、式 4 を囲むスコープ
        Expr {
            ty: i32,
            temp_lifetime: Some(
                Node(1),
            ),
            span: oneplustwo.rs:2:13: 2:18 (#0),
            kind: Scope {
                region_scope: Node(5),
                lint_level: Explicit(
                    HirId {
                        owner: DefId(0:3 ~ oneplustwo[6932]::main),
                        local_id: 5,
                    },
                ),
                value: e4,
            },
        },
        // 式 6、文を囲むブロック
        Expr {
            ty: (),
            temp_lifetime: Some(
                Node(9),
            ),
            span: oneplustwo.rs:1:11: 3:2 (#0),
            kind: Block {
                body: Block {
                    targeted_by_break: false,
                    region_scope: Node(8),
                    opt_destruction_scope: None,
                    span: oneplustwo.rs:1:11: 3:2 (#0),
                    // 下記の文 0 への参照
                    stmts: [
                        s0,
                    ],
                    expr: None,
                    safety_mode: Safe,
                },
            },
        },
        // 式 7、式 6 内のブロックを囲むスコープ
        Expr {
            ty: (),
            temp_lifetime: Some(
                Node(9),
            ),
            span: oneplustwo.rs:1:11: 3:2 (#0),
            kind: Scope {
                region_scope: Node(9),
                lint_level: Explicit(
                    HirId {
                        owner: DefId(0:3 ~ oneplustwo[6932]::main),
                        local_id: 9,
                    },
                ),
                value: e6,
            },
        },
        // 式 7 を囲む破棄スコープ
        Expr {
            ty: (),
            temp_lifetime: Some(
                Node(9),
            ),
            span: oneplustwo.rs:1:11: 3:2 (#0),
            kind: Scope {
                region_scope: Destruction(9),
                lint_level: Inherited,
                value: e7,
            },
        },
    ],
    stmts: [
        // let 文
        Stmt {
            kind: Let {
                remainder_scope: Remainder { block: 8, first_statement_index: 0},
                init_scope: Node(1),
                pattern: Pat {
                    ty: i32,
                    span: oneplustwo.rs:2:9: 2:10 (#0),
                    kind: Binding {
                        mutability: Not,
                        name: "x",
                        mode: ByValue,
                        var: LocalVarId(
                            HirId {
                                owner: DefId(0:3 ~ oneplustwo[6932]::main),
                                local_id: 7,
                            },
                        ),
                        ty: i32,
                        subpattern: None,
                        is_primary: true,
                    },
                },
                initializer: Some(
                    e5,
                ),
                else_block: None,
                lint_level: Explicit(
                    HirId {
                        owner: DefId(0:3 ~ oneplustwo[6932]::main),
                        local_id: 6,
                    },
                ),
            },
            opt_destruction_scope: Some(
                Destruction(1),
            ),
        },
    ],
}