MIR 借用チェック
借用チェックは Rust の「秘伝のタレ」です。これは、いくつかの性質を 強制する役割を担っています。
- すべての変数が、使用される前に初期化されていること。
- 同じ値を 2 回ムーブできないこと。
- 借用されている間は値をムーブできないこと。
- 可変に借用されている間は、その参照を通じる場合を除き、プレースにアクセスできないこと。
- 不変に借用されている間は、プレースを変更できないこと。
- など
借用チェッカーは MIR 上で動作します。古い実装は HIR 上で動作していました。 MIR 上で借用チェックを行うことには、いくつかの利点があります。
- MIR は HIR よりも はるかに 複雑ではありません。徹底的な脱糖衣により、 借用チェッカー内のバグを防ぎやすくなります。(興味がある場合は、 MIR ベースの借用チェッカーが修正するバグの一覧をこちらで確認できます。)
- さらに重要なのは、MIR を使用することで “非レキシカルライフタイム” が可能になることです。これは制御フローグラフから 導出されるリージョンです。
借用チェッカーの主要なフェーズ
借用チェッカーのソースは
the rustc_borrowck crate にあります。主なエントリーポイントは
mir_borrowck クエリです。
- まず、MIR の ローカルコピー を作成します。以降の手順では、 計算している新しいリージョンへの参照を含めるように型などを変更するため、 このコピーをインプレースで変更します。
- 次に、
replace_regions_in_mirを呼び出してローカルの MIR を変更します。 特に、この関数は MIR 内のすべての リージョン を新しい 推論変数 に置き換えます。 - 次に、どのデータがいつムーブされるかを計算する、いくつかの データフロー解析 を実行します。
- 次に、MIR 全体に対して 2 回目の型チェック を行います。 この型チェックの目的は、異なるリージョン間のすべての制約を決定することです。
- 次に、リージョン推論 を行います。これは各リージョンの値、 つまり基本的には、収集した制約に従って各ライフタイムが有効でなければならない 制御フローグラフ上のポイントを計算します。
- この時点で、各ポイントにおける「スコープ内の借用」を計算できます。
- 最後に、MIR をもう一度走査し、そこで行われるアクションを確認して
エラーを報告します。たとえば、
*a + 1のような文を見つけた場合、 変数aが初期化されていること、および可変に借用されていないことを チェックします。どちらかに該当すると、エラーを報告する必要があります。 このチェックを行うには、これまでのすべての解析結果が必要です。