Slide 1

Slide 1 text

Rustソースコードのざっくり とした歩き方 🦀 Takayuki Maeda / TaKO8Ki

Slide 2

Slide 2 text

● Rust committer (member of compiler contributors team and diagnostic working group) ● Rust Foundation 2023 Fellow Takayuki Maeda / TaKO8Ki @TaKO8Ki @TaKOBKi

Slide 3

Slide 3 text

テーマ

Slide 4

Slide 4 text

rustcのコードをほとんど読んだことないRustacean がコントリビュートするための ざっくり入門編

Slide 5

Slide 5 text

セットアップ

Slide 6

Slide 6 text

セットアップ 「Rust Compiler Development Guide」という素晴らしいドキュメントがある。
 
 
 
 
 ref: https://rustc-dev-guide.rust-lang.org

Slide 7

Slide 7 text

とりあえずgit cloneしてみる。 $ git clone https://github.com/rust-lang/rust.git $ cd rust

Slide 8

Slide 8 text

セットアップ rustリポジトリのbuildにはx.pyというツールを使います。これで標準ライブラリ含めて 丸っとbuildできます。
 ref: https://rustc-dev-guide.rust-lang.org/building/bootstrapping.html

Slide 9

Slide 9 text

次にsetupしてみる。色々出てくるので最後compilerを選択する。 $ ./x.py setup

Slide 10

Slide 10 text

VSCodeユーザー向けに setting.jsonが自動的に追加される。 ref: Configuring rust-analyzer for rustc

Slide 11

Slide 11 text

その他サブコマンド (cargoと同じ感じ): $ ./x.py check $ ./x.py build $ ./x.py test $ ./x.py fmt $ ./x.py clean

Slide 12

Slide 12 text

いよいよ、buildしてみる。 $ ./x.py build

Slide 13

Slide 13 text

buildしたcompilerをcargoやrustcで使う。 $ rustup toolchain link stage1 build/[your host]/stage1 $ cargo +stage1 -vV $ rustc +stage1 -vV

Slide 14

Slide 14 text

準備が整ったのでとりあえずテストを実行してみる。 $ ./x.py test

Slide 15

Slide 15 text

セットアップ デバッグはどうやるのか?
 ref: https://rustc-dev-guide.rust-lang.org/compiler-debugging.html

Slide 16

Slide 16 text

backtraceが欲しい時は、 $ RUST_BACKTRACE=1 cargo +stage1 build

Slide 17

Slide 17 text

エラーの発生箇所が知りたい場合は、 $ RUSTFLAGS='-Z track-diagnostics' cargo +stage1 build

Slide 18

Slide 18 text

また、Rustではloggingにtracingというtokio organizationで開発されて いるcrateを使っている。 ref: Using tracing to debug the compiler $ RUSTC_LOG=rustc_parse=debug cargo +stage1 build

Slide 19

Slide 19 text

セットアップ 基本は、修正 → UIテスト追加 → ./x.pyでテスト実行して壊れてないか確認 → プルリク の流れが多い。


Slide 20

Slide 20 text

コードを読んでみる

Slide 21

Slide 21 text

コードを読んでみる 全ては紹介しきれないので、まず、比較的優しい気がするparserを読んでみる。parse はparseがprefixとしてつくmethodやfunctionを目印に読んでいけばいい。
 
 Rustのparserはトップダウンな再帰下降パーサー。
 ref: https://rustc-dev-guide.rust-lang.org/overview.html#lexing-and-parsing

Slide 22

Slide 22 text

entry pointは、 - Parser::parse_crate_mod - Parser::parse_mod

Slide 23

Slide 23 text

parse_modを読み進めてみる。

Slide 24

Slide 24 text

parse_modを読み進めてみる。 上から順に見ていくと、 ここでloopでitemをparseしてそう

Slide 25

Slide 25 text

次にparse_itemに飛んでみる。

Slide 26

Slide 26 text

parse_item_を実行しているのでそっちに行ってみる。

Slide 27

Slide 27 text

parse_item_はこんな感じなのでそれっぽいparse_item_commonを見て みる。

Slide 28

Slide 28 text

parse_item_はこんな感じなのでそれっぽいparse_item_commonを見て みる。

Slide 29

Slide 29 text

まだコアの実装ぽいところにきて無さそうなので、parse_item_common_に ジャンプする。

Slide 30

Slide 30 text

まだコアの実装ぽいところにきて無さそうなので、parse_item_common_に ジャンプする。

Slide 31

Slide 31 text

なんかそれっぽくなってきた。 Parser::parse_item_commont_

Slide 32

Slide 32 text

なんかそれっぽくなってきた。 Parser::parse_item_commont_

Slide 33

Slide 33 text

拡大すると、なんか色々やってそうなmethodが見える。

Slide 34

Slide 34 text

ついにparse_item_kindに辿り着いた。

Slide 35

Slide 35 text

例えばここでenumをparseしてる。

Slide 36

Slide 36 text

せっかくなので、parse_item_enumも覗いてみる。

Slide 37

Slide 37 text

確かにmethodの下の方でコンマ区切りでEnum variantをparseしてそう。

Slide 38

Slide 38 text

では、ここで変更加えてbuildしてみる。 例えばこのエラーメッセージでリポジトリ 内を検索してみると

Slide 39

Slide 39 text

するとUIテスト用のファイルが見つかる。 tests/ui/structs-enums/issue-103869.rs

Slide 40

Slide 40 text

コードを読んでみる UIテストとは何か?
 > tests that check the stdout/stderr from the compilation and/or running the resulting executable
 
 コンパイルによるstdout/stderrと
 実行可能ファイルを実行した結果をチェックするためのテスト 
 
 
 ref: https://rustc-dev-guide.rust-lang.org/tests/compiletest.html#test-suites

Slide 41

Slide 41 text

では適当なdebug用のcrateを作ってmain.rsに下記をコピペしてみる。

Slide 42

Slide 42 text

試しにstage1コンパイラでbuildしてみると、 $ cargo +stage1 build

Slide 43

Slide 43 text

こういうエラーが得られる。

Slide 44

Slide 44 text

こういうエラーが得られる。 さっきparse_item_enumで見つけたエ ラーがある

Slide 45

Slide 45 text

試しにエラーメッセージを変更してみる。 perhaps you meant to use `struct` here foobar

Slide 46

Slide 46 text

再度buildする。 $ ./x.py build

Slide 47

Slide 47 text

もう一度デバッグ用のcrateをbuildしてみると、確かにエラーが変わってる。

Slide 48

Slide 48 text

これであなたもRustコントリビューター 🦀

Slide 49

Slide 49 text

コードを読んでみる rustc_parseの他にもRustリポジトリにはさまざまなcrateがある。
 - rustc_ast_lowering
 - rustc_ast_passes
 - rustc_hir
 - rustc_hir_typeck
 - rustc_borrowck
 などなど。


Slide 50

Slide 50 text

コードを読んでみる 例えば rustc_ast_lowering はrustc_parseで作ったASTをHIRにloweringするため のcrate。lowerがprefixなmethod、functionが目印。


Slide 51

Slide 51 text

rustc_ast_loweringのentry pointは、 rustc_ast_lowring::lower_to_hir

Slide 52

Slide 52 text

同じように覗いてみると、

Slide 53

Slide 53 text

同じように覗いてみると、 ast_indexごとにlower_nodeを呼んでそう

Slide 54

Slide 54 text

lower_nodeの実装は、

Slide 55

Slide 55 text

ここまでくるとなんかいけそう

Slide 56

Slide 56 text

同じように下に読み進めていけば良さそう

Slide 57

Slide 57 text

コードを読んでみる 基本はこんな感じで下記のようなcrateなら読める。
 - rustc_resolve
 - rustc_hir
 - rustc_hir_typeck
 
 rustc_borrwckとかは割と複雑で難しい。


Slide 58

Slide 58 text

実際にissueに取り組 んでみる

Slide 59

Slide 59 text

実際にissueに取り組んでみる 今回は自分が過去に取り組んだ比較的シンプルなissueを参考に見てみます。
 
 “consider dereferencing here” help doesn’t account for operator precedence of the deref operator · Issue #105429 · rust-lang/rust


Slide 60

Slide 60 text

issueを見ると、下記のソースコードが与えられた時に、

Slide 61

Slide 61 text

このようなエラーが得られるとあります。(現時点では修正済み)

Slide 62

Slide 62 text

正しくないのはこの箇所です。

Slide 63

Slide 63 text

実際はこのようにdereferenceする必要があります。

Slide 64

Slide 64 text

検索したり-Zフラグを使ってエラーの発生箇所を特定してみると、 ref: rustc_trait_selection/src/traits/error_reporting/suggestions.rs#L778

Slide 65

Slide 65 text

検索したり-Zフラグを使ってエラーの発生箇所を特定してみると、 ref: rustc_trait_selection/src/traits/error_reporting/suggestions.rs#L778

Slide 66

Slide 66 text

やる必要があるのは、dereferenceする対象がmethodのreceiverの際に 特別なハンドリングをすること。 ref: rustc_trait_selection/src/traits/error_reporting/suggestions.rs#L778

Slide 67

Slide 67 text

何から始めたらいいか分からないと仮定してまず、spanに定義ジャンプしてみ る。 ref: rustc_trait_selection/src/traits/error_reporting/suggestions.rs#L778

Slide 68

Slide 68 text

ありました。これがspan。ObligationCauseのspanというfieldから取れるっ ぽい。 ref: rustc_trait_selection/src/traits/error_reporting/suggestions.rs

Slide 69

Slide 69 text

obligationはここでも使われてる。codeという概念があるらしい。 ref: rustc_trait_selection/src/traits/error_reporting/suggestions.rs

Slide 70

Slide 70 text

obligation.causeのなかにエラー発生箇所のspanなどの情報が詰められて そう?なことが分かる。 今回のissueではintoなのでargはありませ んが、これは引数のことっぽい。 ref: rustc_trait_selection/src/traits/error_reporting/suggestions.rs

Slide 71

Slide 71 text

obligation.causeのなかにエラー発生箇所のspanなどの情報が詰められて そう?なことが分かる。 また、hir_idというのが取れると、それがどう いうNodeかチェックできるっぽい ref: rustc_trait_selection/src/traits/error_reporting/suggestions.rs

Slide 72

Slide 72 text

このNode enumの定義を見てみる。 ref: rustc_trait_selection/src/traits/error_reporting/suggestions.rs

Slide 73

Slide 73 text

このNode enumの定義を見てみる。

Slide 74

Slide 74 text

このNode enumの定義を見てみる。

Slide 75

Slide 75 text

このNode enumの定義を見てみる。

Slide 76

Slide 76 text

さらにExpr structに飛んでみる。

Slide 77

Slide 77 text

Exprはkindを持ってるので、これでmethodのreceiverかどうか判別できる のでは?

Slide 78

Slide 78 text

でもarg_hir_idはあるが、対象のexprがmethod callで対象がその receiverかどうか判別できないとダメそう。 試しにFunctionArgumentObligationを見に行ってみる。

Slide 79

Slide 79 text

それっぽいのがあるので、いけそう!

Slide 80

Slide 80 text

ということでこの実装をcall_hir_idを使って修正してみる。

Slide 81

Slide 81 text

No content

Slide 82

Slide 82 text

call_hir_idを元にexprがmethod callかど うか判別できた

Slide 83

Slide 83 text

あとはmethod callでかつ対象がそのreceiverの時だけ()で 囲ってdereferenceすればいい

Slide 84

Slide 84 text

実際にissueに取り組んでみる あとはUIテストを書いて全てのテストにパスすることを確認して、プルリクの完成
 
 Suggest dereferencing receiver arguments properly by TaKO8Ki · Pull Request #105595 · rust-lang/rust


Slide 85

Slide 85 text

まとめ

Slide 86

Slide 86 text

© Money Forward, Inc. まとめ ● 基本は「Rust Compiler Development Guide」を読めば大体のことが分 かる。
 ● 下に下に掘り下げていけば割と読める。
 ● 分からないことはある程度推測しながら身につけていけば、全体像が見え なくても修正を加えたりできる。


Slide 87

Slide 87 text

We are hiring!

Slide 88

Slide 88 text

No content