rust Analyzerは、優れたIDEエクスペリエンスをRustに実現することを目的とした、Rustエコシステムの新たな取り組みだ。
Rustのツール開発において、コンパイラのパフォーマンスは常に重要なポイントであり、コンパイル時間はリリースを重ねる毎に改善されている。その一方で、Igor Matuszewski氏がRust Belt Rust Conferenceの講演で述べたように、RustのIDEサポートについても活発な開発が続けられている。
この3年間、さまざまな新ツールが登場し、ツール間のインテグレーションも改善され、Rustを取り巻く環境は大きく変わりました。しかしながら、IDEでRustを使うというストーリに関しては、まだ完成の域に達していないというのが正直な印象です。
この開発はRLS 2.0ワーキンググループの指導の下で進められていて、その重要なコンポーネントのひとつがRust Analyzerである。InfoQは今回、Rust Analyzerの主要なコントリビュータであるAleksey Kladov氏と、Rust Core TeamメンバのSteve Klabnik氏に、その詳細を聞くことができた。
Rustは最近多くの注目を集めていて、言語は進化し、そのエコシステムやツーリングも急速に成長しています。Rustの現在の完成度と、今後数年間で何が期待できるのか、教えて頂けますか?
Kkabnik: "完成度(Maturity)"という言葉には、さまざまな解釈がありますが、私の考える基準は、実際の製品開発にRustを使用している企業です。現時点では、次のような企業があります。
- Amazon
- Microsoft
その他。FAANGの5社中3社というのは、悪い成績ではありません。
一般論として、Rustはスローダウンしています。新機能は少なくなり、既存機能の改善に重点が移っているのです。例えば先日、async/awaitが公開されましたが、現在はより多くの開発が診断などの機能に向けられています。今後5年間にいくつかの大きな機能を追加する予定はあります。ですが、async/awaitが主としてネットワークアプリケーションを対象としたものであるように、今後の新機能は特定の目的に対して有用なものであって、すべてのRustプログラマを対象としたものにはならないでしょう。例えば"const generis"。これは型だけでなく、整数に対してもジェネリックなコードを記述可能にするものですが、特に数値ライブラリにおいて有用なものです。しかし総論としては、これらの新機能も、これまでの大規模なものに比べるとゆっくりと追加されることになります。
IDE統合に関して、現在のRustコンパイラにどのような制限があるのか、簡単に説明してください。Rust Analyzerプロジェクトの目標は何なのでしょうか?
Kladov: 制限はRust言語特有のものではなく、一般的なコマンドラインとIDEコンパイラとの違いに関するものです。
その中心となるのは、コマンドライン(あるいはバッチ)コンパイラがスループット(1秒間に何千行コンパイル可能か)を重視しているのに対して、IDEコンパイラはレイテンシ(ユーザがコードの一部分を新たに入力してから何ミリ秒で、正しい補完候補を表示できるか)を重視している点です。スループットとレイテンシの常として、この2つの目標にはまったく違った最適化(および高レベルのアーキテクチャ)が必要になります。一般論で言えば、高スループットのみを念頭に開発されたコンパイラを低レイテンシの要求にレトロフィットするというのは、非常に難しい作業です。
もうひとつは、無効なコードの扱い方の違いです。従来のコンパイラは通常、フェーズの進行として構成されています。各フェーズが非構造的なインプットを受け入れて、そのインプットの正当性をチェックし、有効であればその上に構造を付加します。特に、初期のフェーズ(パースなど)でエラーが発生した場合、そのコードに対して以降のフェーズ(型チェックなど)は実行されないのが一般的です。要するに、"正しいコード"がハッピーケースであって、それ以外はすべてエラー状態として扱われる可能性があるのです。対照的にIDEでは、ユーザが常にコードを修正しているため、コードはいつも不正な状態にあります。コードが有効になるとすぐ、IDEの処理は終了して、バッチコンパイルが開始されます。ですからIDE用のコンパイラは、不完全ないし不正なコードを受け入れて、そのようなコードに補完などのIDE機能を提供することが必要なのです。
rust-analyzerプロジェクトの最終的な目標は、レイテンシとスループットという2つの次元で優れたスコアを獲得できる、単一のRustコンパイラを提供することです。ですが、この目標は遠大なものなので、現時点では事実上2つのフロントエンドが存在する段階にあります。
- rustc — 完成度の高いバッチコンパイラ
- rust-analyzer — ごく初期段階のIDE/レイテンシ指向コンパイラ
各フロントエンドは、現時点ではほとんどコードを共有していないので、当面の技術的な目標は、比較的共有の容易なコードを共通化することです。
このプロジェクトは、Rust LSP実装に代わるものなのでしょうか?
Kkadov: 現時点ではそうではありません。試験的なものであって、公式なLSPとして推奨できるレベルにはないからです。しかしながら、現時点での暫定的なものですが、近い将来にrust-analyzerをRLSの後継とする計画はあります。
コンパイラのリファクタリングが今後どのような方向に進むのか、詳しく教えてください。
CKladov: 基本的な考え方は、コンパイラをもっと遅延させる、ということです。IDEで低レイテンシを実現するための重要なトリックのひとつに、動作を可能な限り避ける、というものがあります。例えば、コード補完を実現するためには、一般的には画面上のコードとその直接的な依存関係だけを解析すれば十分です。プロジェクトにある他の500万行のコードに何が書かれているのかを、気にする必要はありません。アイデアは単純ですが、コンパイラに他のコードを見ないようにさせるというのは、実際にはかなりトリッキーで、多くの開発作業を必要とします。具体的に計画しているのは、次のようなことです。
- 空白やコメントを含んだフルフィデリティ(full-fidelity)な構文木表現への移行
- ひとつのコンパイラインスタンスが複数のコンパイルユニットを処理可能な"マルチクレート(multi-crate)"モードの追加
- コンパイラプロセスの永続化と、ファイルの差分をコンパイラに送信可能にすること
これらはすべて、rust-analyzerにはすでに実装されていますが、どちらかといえば概念実証(proof-of-concept)的なものになっています。難しいのは、現在処理されているユーザのコードに影響を与えずに、これらすべてを実際のコンパイラに移行することです。
Rust Analyzerはまだアルファ段階で、ソースからビルドする必要がある。
$ git clone https://github.com/rust-analyzer/rust-analyzer
$ cd rust-analyzer
$ cargo xtask install
試してみたいと思うのであれば、マニュアルの確認も忘れてはならない。