本家Rustコンパイラのソースを読もうとしてみる（4）

# 前回までのあらすじ

[Guide to Rustc Development](https://rustc-dev-guide.rust-lang.org/about-this-guide.html)という便利なガイドに沿って、Rustの本家コンパイラである[rust-lang/rust](https://github.com/rust-lang/rust)のソースコードを読んでみようという試み。なかなか終わらない「Source Code Representations」の、MIRのあたりから。

[目次（初回）](https://qiita.com/0yoyoyo/items/eba97a019d0e60324263)

# Source Code Representations

Token列、AST、HIRときたので、今回はMIR生成を見ていく。このあたりからQuery systemがガンガン使われるので、シーケンシャルな感覚でいると流れが追いづらい。内容的にもこれまでより難しいので、前提となる知識から整理していこう。


### CFG

MIRの構造は[Control-flow graph](https://en.wikipedia.org/wiki/Control-flow_graph)（CFG）をベースにしている。私は詳しくないが、最適化コンパイラではそれなりに使われるデータ構造と思われる。MIRにおいてCFGがどのように表されるのかの具体例は、ガイドの説明が結構丁寧なのでそちらを参照するのが分かりやすい。基本的には基本ブロック（Basic Block）が並び、典型的には基本ブロックの中には複数のstatementと単独のterminatorが配置される。terminatorは次に進む基本ブロックを指し示しており、場合によっては条件で決まる複数の行き先をもつ。

```
（<n>、<m>には番号が入る）
bb<n>: {
    statement
    statement
    ...
    terminater -> bb<m>;
}
```

データ構造がそれなりに複雑なので、まずはこの構造とソースの対応を確認しておこう。

MIRの生成は`rustc_mir_build`で定義されている`mir_built`のQueryから開始される。その実体となる関数`mir_build()`のシグネチャで出現するデータ型を調べてみる。

```rust:rustc_mir_build/src/build/mod.rs
crate fn mir_built<'tcx>(
    tcx: TyCtxt<'tcx>,
    def: ty::WithOptConstParam<LocalDefId>,
) -> &'tcx ty::steal::Steal<Body<'tcx>> {
    if let Some(def) = def.try_upgrade(tcx) {
        return tcx.mir_built(def);
    }

    tcx.alloc_steal_mir(mir_build(tcx, def))
}

/// Construct the MIR for a given `DefId`.
fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> {
...
}
```

`def`として`DefID`を受け取り、`Body`という型を返している。

ガイドにもある通り、MIRの生成は関数の本体ブロックや、`static`、`const`の初期化ブロックなどに対して行われる。考えてみれば、プログラムにおいて**実行**される記述はそのような部分に絞られるのだろう。そのため、ASTやHIRのようにクレート全体を渡すのではなく、`DefID`を渡すことでソースのブロック単位で変換を行うような作りになっている。（Query戦略のほうが理由としては大きいかもしれないが、、）

関数の結果としては、`Body`という型を返しており、この型名からもブロック単位で処理が行われていることが読み取れる。では、`Body`の構造について掘り下げていこう。

`Body`は様々な情報をもっているが、その中に`basic_blocks`というベクタがある。これは、MIRが複数の基本ブロックで構成されているという構造と一致しそうだ。ベクタの要素としては`BasicBlock`と`BasicBlockData`をもっている。`BasicBlockData`には`Statement`のベクタと`Terminater`があり、これも基本ブロックの内部構造と一致していることが分かる。`BasicBlock`は、`BasicBlockData`に紐づくインデックスを保持しているようで、見る限り`BasicBlock`を使ったアクセスのほうが多用されている。（ちなみに執筆時点のガイドには、MIRは`Mir`という型で表されると記載されているが、そのような型は見当たらなかった）

```rust:rustc_middle/src/mir/mod.rs
/// The lowered representation of a single function.
#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable)]
pub struct Body<'tcx> {
    /// A list of basic blocks. References to basic block use a newtyped index type `BasicBlock`
    /// that indexes into this vector.
    basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
...
}
...
rustc_index::newtype_index! {
    pub struct BasicBlock {
        derive [HashStable]
        DEBUG_FORMAT = "bb{}",
        const START_BLOCK = 0,
    }
}
...
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
pub struct BasicBlockData<'tcx> {
    /// List of statements in this block.
    pub statements: Vec<Statement<'tcx>>,

    /// Terminator for this block.
    ///
    /// N.B., this should generally ONLY be `None` during construction.
    /// Therefore, you should generally access it via the
    /// `terminator()` or `terminator_mut()` methods. The only
    /// exception is that certain passes, such as `simplify_cfg`, swap
    /// out the terminator temporarily with `None` while they continue
    /// to recurse over the set of basic blocks.
    pub terminator: Option<Terminator<'tcx>>,
...
}
```

`Terminator`の中身についても一応確認しておこう。`Terminator`の構造体は`TerminatorKind`をもっており、このenumの要素の多くは内部で`BasicBlock`をもっている。これは次に向かう基本ブロックを意味していると思われる。条件によって分岐するような場合は`BasicBlock`をベクタとして保持している。

```rust:
#[derive(Clone, TyEncodable, TyDecodable, HashStable, PartialEq)]
pub enum TerminatorKind<'tcx> {
    /// Block should have one successor in the graph; we jump there.
    Goto { target: BasicBlock },

    /// Operand evaluates to an integer; jump depending on its value
    /// to one of the targets, and otherwise fallback to `otherwise`.
    SwitchInt {
...
        /// Possible branch sites. The last element of this vector is used
        /// for the otherwise branch, so targets.len() == values.len() + 1
        /// should hold.
        //
        // This invariant is quite non-obvious and also could be improved.
        // One way to make this invariant is to have something like this instead:
        //
        // branches: Vec<(ConstInt, BasicBlock)>,
        // otherwise: Option<BasicBlock> // exhaustive if None
        //
        // However we’ve decided to keep this as-is until we figure a case
        // where some other approach seems to be strictly better than other.
        targets: Vec<BasicBlock>,
    },
...
}
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
pub struct Terminator<'tcx> {
    pub source_info: SourceInfo,
    pub kind: TerminatorKind<'tcx>,
}
```

これで、CFGを構成する基本ブロックの構造と、その構造のソース内での表現を確認することができた。


### THIR

まだMIRには行けない。HIRからMIRに変換する前に、**Typed HIR**（THIR）へ変換するという処理が入っている。THIRはHigh-level Abstract IR (HAIR)と呼ばれることも多く、また、全体構成だと省略されていることもあったりして、ちょっと混乱する。この変換では、暗黙的な型強制を明示したり、メソッドの呼び出し形式を変更したりするようだ。THIRも、ソース全体をまとめて変換するのではなく、式に対して必要に応じて変換されているようだ。

THIRへの変換処理は主に`rustc_mir_build::thir`で実施されており、式に対する処理は`hir::Expr`に対する`make_mirror()`メソッドから始まる。

```rust:rustc_mir_build/src/thir/cx/expr.rs
impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr<'tcx> {
    type Output = Expr<'tcx>;

    fn make_mirror(self, cx: &mut Cx<'_, 'tcx>) -> Expr<'tcx> {
        let temp_lifetime = cx.region_scope_tree.temporary_scope(self.hir_id.local_id);
        let expr_scope = region::Scope { id: self.hir_id.local_id, data: region::ScopeData::Node };

        debug!("Expr::make_mirror(): id={}, span={:?}", self.hir_id, self.span);

        let mut expr = make_mirror_unadjusted(cx, self);

        // Now apply adjustments, if any.
        for adjustment in cx.typeck_results().expr_adjustments(self) {
            debug!("make_mirror: expr={:?} applying adjustment={:?}", expr, adjustment);
            expr = apply_adjustment(cx, self, expr, adjustment);
        }

        // Next, wrap this up in the expr's scope.
        expr = Expr {
            temp_lifetime,
            ty: expr.ty,
            span: self.span,
            kind: ExprKind::Scope {
                region_scope: expr_scope,
                value: expr.to_ref(),
                lint_level: LintLevel::Explicit(self.hir_id),
            },
        };
...
        // OK, all done!
        expr
    }
}
```

処理は`make_mirror_unadjusted()`へと続いていき、ここで式の種別ごとの変換に実施される。一例としてメソッド呼び出しの変換処理を見てみると、ソース内のコメントにもあるように`a.b(c)`というメソッドの呼び出しを`Trait::b(a, c)`という形式に変換している。変換後の形式はUFCS（Unified Function Call Syntax）と呼ばれるらしい。知らなかった。

```rust:rustc_mir_build/src/thir/cx/expr.rs
fn make_mirror_unadjusted<'a, 'tcx>(
    cx: &mut Cx<'a, 'tcx>,
    expr: &'tcx hir::Expr<'tcx>,
) -> Expr<'tcx> {
    let expr_ty = cx.typeck_results().expr_ty(expr);
    let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);

    let kind = match expr.kind {
        // Here comes the interesting stuff:
        hir::ExprKind::MethodCall(_, method_span, ref args, fn_span) => {
            // Rewrite a.b(c) into UFCS form like Trait::b(a, c)
            let expr = method_callee(cx, expr, method_span, None);
            let args = args.iter().map(|e| e.to_ref()).collect();
            ExprKind::Call { ty: expr.ty, fun: expr.to_ref(), args, from_hir_call: true, fn_span }
        }
...
    };

    Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind }
}
```

`make_mirror()`は`Cx`という型のメソッドである`mirror()`から呼び出され、この`mirror()`がMIRへの変換中に多用されることになる。

```rust:rustc_mir_build/src/thir/cx/mod.rs
impl<'a, 'tcx> Cx<'a, 'tcx> {
    /// Normalizes `ast` into the appropriate "mirror" type.
    crate fn mirror<M: Mirror<'tcx>>(&mut self, ast: M) -> M::Output {
        ast.make_mirror(self)
    }
...
}
```

THIRへの変換はMIR生成のところどころで現れるため、意識しておくと読みやすくなるだろう。


### MIR

ようやくMIRへの変換処理を読む準備が整った。上でシグネチャだけ確認した`mir_build()`に戻り、その中身を追っていこう。ここでは、関数定義の本体ブロックを想定して見ていく。

まずは`DefID`に基づいて`BodyID`を取り出した後、`build::construct_fn()`に進んでいく。

```rust:rustc_mir_build/src/build/mod.rs
/// Construct the MIR for a given `DefId`.
fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> {
    let id = tcx.hir().local_def_id_to_hir_id(def.did);

    // Figure out what primary body this item has.
    let (body_id, return_ty_span, span_with_body) = match tcx.hir().get(id) {
        Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(_, decl, body_id, _, _), .. }) => {
            (*body_id, decl.output.span(), None)
        }
        Node::Item(hir::Item {
            kind: hir::ItemKind::Fn(hir::FnSig { decl, .. }, _, body_id),
            span,
            ..
        })
        | Node::ImplItem(hir::ImplItem {
            kind: hir::ImplItemKind::Fn(hir::FnSig { decl, .. }, body_id),
            span,
            ..
        })
        | Node::TraitItem(hir::TraitItem {
            kind: hir::TraitItemKind::Fn(hir::FnSig { decl, .. }, hir::TraitFn::Provided(body_id)),
            span,
            ..
        }) => {
            // Use the `Span` of the `Item/ImplItem/TraitItem` as the body span,
            // since the def span of a function does not include the body
            (*body_id, decl.output.span(), Some(*span))
        }
...
    };

    // If we don't have a specialized span for the body, just use the
    // normal def span.
    let span_with_body = span_with_body.unwrap_or_else(|| tcx.hir().span(id));

    tcx.infer_ctxt().enter(|infcx| {
        let cx = Cx::new(&infcx, def, id);
        let body = if let Some(ErrorReported) = cx.typeck_results().tainted_by_errors {
            build::construct_error(cx, body_id)
        } else if cx.body_owner_kind.is_fn_or_closure() {
...
            let body = tcx.hir().body(body_id);
...
            let mut mir = build::construct_fn(
                cx,
                id,
                arguments,
                safety,
                abi,
                return_ty,
                return_ty_span,
                body,
                span_with_body
            );
            mir.yield_ty = yield_ty;
            mir
        } else {
...
        };

        lints::check(tcx, &body, def.did);
...
        body
    })
}
```

`construct_fn()`では、まず冒頭部分で`Builder::new()`により`Builder`を生成していることに注目しよう。ついでに、`Cx`として`hir`が渡されていることも意識しておく。この関数は後から他の部分も見るので、全体を載せている。

```rust:rustc_mir_build/src/build/mod.rs
fn construct_fn<'a, 'tcx, A>(
    hir: Cx<'a, 'tcx>,
    fn_id: hir::HirId,
    arguments: A,
    safety: Safety,
    abi: Abi,
    return_ty: Ty<'tcx>,
    return_ty_span: Span,
    body: &'tcx hir::Body<'tcx>,
    span_with_body: Span
) -> Body<'tcx>
where
    A: Iterator<Item = ArgInfo<'tcx>>,
{
    let arguments: Vec<_> = arguments.collect();

    let tcx = hir.tcx();
    let tcx_hir = tcx.hir();
    let span = tcx_hir.span(fn_id);

    let fn_def_id = tcx_hir.local_def_id(fn_id);

    let mut builder = Builder::new(
        hir,
        span_with_body,
        arguments.len(),
        safety,
        return_ty,
        return_ty_span,
        body.generator_kind,
    );

    let call_site_scope =
        region::Scope { id: body.value.hir_id.local_id, data: region::ScopeData::CallSite };
    let arg_scope =
        region::Scope { id: body.value.hir_id.local_id, data: region::ScopeData::Arguments };
    let mut block = START_BLOCK;
    let source_info = builder.source_info(span);
    let call_site_s = (call_site_scope, source_info);
    unpack!(
        block = builder.in_scope(call_site_s, LintLevel::Inherited, |builder| {
            if should_abort_on_panic(tcx, fn_def_id, abi) {
                builder.schedule_abort();
            }

            let arg_scope_s = (arg_scope, source_info);
            // `return_block` is called when we evaluate a `return` expression, so
            // we just use `START_BLOCK` here.
            unpack!(
                block = builder.in_breakable_scope(
                    None,
                    START_BLOCK,
                    Place::return_place(),
                    |builder| {
                        builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
                            builder.args_and_body(
                                block,
                                fn_def_id.to_def_id(),
                                &arguments,
                                arg_scope,
                                &body.value,
                            )
                        })
                    },
                )
            );
            // Attribute epilogue to function's closing brace
            let fn_end = span_with_body.shrink_to_hi();
            let source_info = builder.source_info(fn_end);
            let return_block = builder.return_block();
            builder.cfg.goto(block, source_info, return_block);
            builder.cfg.terminate(return_block, source_info, TerminatorKind::Return);
            // Attribute any unreachable codepaths to the function's closing brace
            if let Some(unreachable_block) = builder.cached_unreachable_block {
                builder.cfg.terminate(unreachable_block, source_info, TerminatorKind::Unreachable);
            }
            return_block.unit()
        })
    );
    assert_eq!(block, builder.return_block());

    let spread_arg = if abi == Abi::RustCall {
        // RustCall pseudo-ABI untuples the last argument.
        Some(Local::new(arguments.len()))
    } else {
        None
    };
    debug!("fn_id {:?} has attrs {:?}", fn_def_id, tcx.get_attrs(fn_def_id.to_def_id()));

    let mut body = builder.finish();
    body.spread_arg = spread_arg;
    body
}
```

`Builder`のメンバを確認しよう。いろいろあるが、`Cx`として`hir`をもつ他、`CFG`という型のメンバをもっている。そしてこの`CFG`は、`basic_blocks`として基本ブロックのベクタを表していることが分かる。これは`Body`に含まれる`basic_blocks`と同じ構造だ。

```rust:rustc_mir_build/src/build/mod.rs
struct Builder<'a, 'tcx> {
    hir: Cx<'a, 'tcx>,
    cfg: CFG<'tcx>,
...
}
...
struct CFG<'tcx> {
    basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
}
```

`CFG`の型には、基本ブロックやその内部データを操作するためのメソッドが定義されている。基本的なところをいくつか示しておくと、新しく基本ブロックを作る`start_new_block()`、`Statement`を追加する`push()`、`Terminator`を設定する`terminate()`などがある。MIRの生成では、これらのメソッドを駆使して、望むような構造を作り上げていくことになる。

```rust:rustc_mir_build/src/build/cfg.rs
impl<'tcx> CFG<'tcx> {
    crate fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> {
        &self.basic_blocks[blk]
    }

    crate fn block_data_mut(&mut self, blk: BasicBlock) -> &mut BasicBlockData<'tcx> {
        &mut self.basic_blocks[blk]
    }

    // llvm.org/PR32488 makes this function use an excess of stack space. Mark
    // it as #[inline(never)] to keep rustc's stack use in check.
    #[inline(never)]
    crate fn start_new_block(&mut self) -> BasicBlock {
        self.basic_blocks.push(BasicBlockData::new(None))
    }
...
    crate fn push(&mut self, block: BasicBlock, statement: Statement<'tcx>) {
        debug!("push({:?}, {:?})", block, statement);
        self.block_data_mut(block).statements.push(statement);
    }
...
    crate fn terminate(
        &mut self,
        block: BasicBlock,
        source_info: SourceInfo,
        kind: TerminatorKind<'tcx>,
    ) {
        debug!("terminating block {:?} <- {:?}", block, kind);
        debug_assert!(
            self.block_data(block).terminator.is_none(),
            "terminate: block {:?}={:?} already has a terminator set",
            block,
            self.block_data(block)
        );
        self.block_data_mut(block).terminator = Some(Terminator { source_info, kind });
    }

    /// In the `origin` block, push a `goto -> target` terminator.
    crate fn goto(&mut self, origin: BasicBlock, source_info: SourceInfo, target: BasicBlock) {
        self.terminate(origin, source_info, TerminatorKind::Goto { target })
    }
}
```

`construct_fn()`の最後を見ると、`builder`に対して`finish()`というメソッドを呼んでいる。この`finish()`メソッドで、作り上げた`cfg`を同じ型である`Body`の`basic_blocks`へと移し、MIRを返すという流れになっている。

```rust:rustc_mir_build/src/build/mod.rs
impl<'a, 'tcx> Builder<'a, 'tcx> {
...
    fn finish(self) -> Body<'tcx> {
        for (index, block) in self.cfg.basic_blocks.iter().enumerate() {
            if block.terminator.is_none() {
                span_bug!(self.fn_span, "no terminator on block {:?}", index);
            }
        }

        Body::new(
            self.cfg.basic_blocks,
            self.source_scopes,
            self.local_decls,
            self.canonical_user_type_annotations,
            self.arg_count,
            self.var_debug_info,
            self.fn_span,
            self.generator_kind,
        )
    }
...
}
```

さて、今度は`construct_fn()`の中段あたりに注目し、`cfg`を作り上げるところを追っていこう。マクロやクロージャが絡み合い複雑になっているが、`args_and_body()`というメソッドが呼ばれている。大きく省略しているが、このメソッドの最後のあたりを見る。

```rust:rustc_mir_build/src/build/mod.rs
impl<'a, 'tcx> Builder<'a, 'tcx> {
...
    fn args_and_body(
        &mut self,
        mut block: BasicBlock,
        fn_def_id: DefId,
        arguments: &[ArgInfo<'tcx>],
        argument_scope: region::Scope,
        ast_body: &'tcx hir::Expr<'tcx>,
    ) -> BlockAnd<()> {
...
        let body = self.hir.mirror(ast_body);
        self.into(Place::return_place(), block, body)
    }
}
```

上で説明した`mirror()`メソッドでTHIRに変換したのち、`into()`というメソッドを呼び出している。この`into()`メソッドは、`eval_into()`を経由して、`into_expr()`を呼び出すことになる。

```rust:rustc_mir_build/src/build/into.rs
impl<'a, 'tcx> Builder<'a, 'tcx> {
    crate fn into<E>(
        &mut self,
        destination: Place<'tcx>,
        block: BasicBlock,
        expr: E,
    ) -> BlockAnd<()>
    where
        E: EvalInto<'tcx>,
    {
        expr.eval_into(self, destination, block)
    }
}

impl<'tcx> EvalInto<'tcx> for ExprRef<'tcx> {
    fn eval_into(
        self,
        builder: &mut Builder<'_, 'tcx>,
        destination: Place<'tcx>,
        block: BasicBlock,
    ) -> BlockAnd<()> {
        let expr = builder.hir.mirror(self);
        builder.into_expr(destination, block, expr)
    }
}
```

では`into_expr()`を見ていく。ここで式の種別ごとに処理が分けられ、それぞれで先ほどの`CFG`のメソッドを使い、MIRが生成されていく。いくつか確認してみよう。

```rust:rustc_mir_build/src/build/expr/into.rs
impl<'a, 'tcx> Builder<'a, 'tcx> {
    /// Compile `expr`, storing the result into `destination`, which
    /// is assumed to be uninitialized.
    crate fn into_expr(
        &mut self,
        destination: Place<'tcx>,
        mut block: BasicBlock,
        expr: Expr<'tcx>,
    ) -> BlockAnd<()> {
...
        let block_and = match expr.kind {
...
            ExprKind::Block { body: ast_block } => {
                this.ast_block(destination, block, ast_block, source_info)
            }
            ExprKind::Match { scrutinee, arms } => {
                this.match_expr(destination, expr_span, block, scrutinee, arms)
            }
...
            ExprKind::LogicalOp { op, lhs, rhs } => {
                // And:
                //
                // [block: If(lhs)] -true-> [else_block: If(rhs)] -true-> [true_block]
                //        |                          | (false)
                //        +----------false-----------+------------------> [false_block]
                //
                // Or:
                //
                // [block: If(lhs)] -false-> [else_block: If(rhs)] -true-> [true_block]
                //        | (true)                   | (false)
                //  [true_block]               [false_block]

                let (true_block, false_block, mut else_block, join_block) = (
                    this.cfg.start_new_block(),
                    this.cfg.start_new_block(),
                    this.cfg.start_new_block(),
                    this.cfg.start_new_block(),
                );

                let lhs = unpack!(block = this.as_local_operand(block, lhs));
                let blocks = match op {
                    LogicalOp::And => (else_block, false_block),
                    LogicalOp::Or => (true_block, else_block),
                };
                let term = TerminatorKind::if_(this.hir.tcx(), lhs, blocks.0, blocks.1);
                this.cfg.terminate(block, source_info, term);

                let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs));
                let term = TerminatorKind::if_(this.hir.tcx(), rhs, true_block, false_block);
                this.cfg.terminate(else_block, source_info, term);

                this.cfg.push_assign_constant(
                    true_block,
                    source_info,
                    destination,
                    Constant { span: expr_span, user_ty: None, literal: this.hir.true_literal() },
                );

                this.cfg.push_assign_constant(
                    false_block,
                    source_info,
                    destination,
                    Constant { span: expr_span, user_ty: None, literal: this.hir.false_literal() },
                );

                // Link up both branches:
                this.cfg.goto(true_block, source_info, join_block);
                this.cfg.goto(false_block, source_info, join_block);
                join_block.unit()
            }
...
        };
...
        block_and
    }
}
```

- `ExprKind::Block`：関数の本体などは全体がブロックで囲われているため、最初はここに入ると思われる。詳細なソースは記載しないが、`ast_block()`、`ast_block_stmts()`と続く。この`ast_block_stmts()`も、Rustにおける束縛の考え方のようなものが反映されていて、深く読み込んだら面白そうな感じだ。ブロック内の各文は`stmt_expr()`へと渡り、いくつか条件はあるものの、特に引っかからないものは`as_temp()`、`expr_as_temp()`と進んでいき、再度`into()`が呼ばれるように見える。つまり、ブロック内の文に対して`into_expr()`を呼び出し、再帰的に処理されていく様子が伺える。
- `ExprKind::Match`：いわゆるプログラムが分岐していくような処理は、大抵ここに入り`match_expr()`に進んでいくと思われるが、この先は結構処理が大きく複雑なのであまり追えていない。
- `ExprKind::LogicalOp`：その代わり、論理演算の処理はMIRにおける分岐の処理がコンパクトにまとまっていて、分かりやすいと思ったので少し説明しておく。ここでは`A && B`のような処理を考えてみよう。
  - 現在は`A`にいる。
  - まず、`start_new_block()`により必要な基本ブロックを作る。全体として真になったときの`true_block`、全体として偽になったときの`false_block`、`B`の処理が入る`else_block`、全てが終わったあとに進んでいく`join_block`だ。
  - 現在地`A`から進む先は条件により`else_block`か`false_block`になるため、`terminate()`でそのように`Terminator`を設定する。
  - `else_block`に進んだ場合、そこから向かう先は`true_block`か`false_block`になるため、こちらも`terminate()`で設定する。
  - `true_block`と`false_block`には`push_assign_constant()`によりそれぞれ`Statement`としてtrueとfalseを設定する。
  - 最後に`goto()`により`true_block`と`false_block`の`Terminator`を`join_block`に設定し、作成した基本ブロックをつなぐ流れができあがる。

完成した`cfg`を上述した通り`Body`の要素として返すことで、MIR生成が完了となる。


# つづく

これでソースコードからMIRまでの変換を見ていくことができた。ここからLLVM IRの生成に進んでいくかと思いきや、次章「Analysis」ではRustの特徴的な機構をいろいろと見ていく（たぶん）。全部は深掘れないと思うのでいくつかピックアップしていこうと思います。

[本家Rustコンパイラのソースを読もうとしてみる（5）](https://qiita.com/0yoyoyo/items/05d5b576cbc319f7579c)←次回