Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Rustソースコードのざっくりとした歩き方 🦀
Search
TaKO8Ki
August 30, 2023
Programming
14
6.1k
Rustソースコードのざっくりとした歩き方 🦀
https://techfeed.io/events/techfeed-experts-night-24
TaKO8Ki
August 30, 2023
Tweet
Share
More Decks by TaKO8Ki
See All by TaKO8Ki
RustのReturn-position impl trait in trait (RPITIT) の実装を雑に見てみる
tako8ki
1
180
Rustで始めるコードファーストなOpenAPI定義の生成 🦀
tako8ki
1
1.6k
簡単なシェルを作ってRustを学ぼう
tako8ki
1
400
How to contribute to Rust and what I have recently been working on
tako8ki
0
240
RustでTUIのSQLクライアントを作った
tako8ki
0
1k
A Ruby version manager written in Rust, which is 7 seconds faster than rbenv
tako8ki
1
1.6k
Other Decks in Programming
See All in Programming
Introduction of Happy Eyeballs Version 2 (RFC8305) to the Socket library
coe401_
1
220
Microservices rules (July 2024) : what good looks like
cer
PRO
0
1.6k
Google's Recipe for Scaling (Web) Security – LocoMocoSec 2024
lweichselbaum
0
170
みんなのオブザーバビリティプラットフォームを作ってるんだがパフォーマンスがやばい #mackerelio #srenext
ne_sachirou
0
380
Exploring the Gradually Lost Technical Skills in the Cloud Native Era
hwchiu
2
3.9k
APIのない大学ログインWebサービスをWKWebViewとJavaScriptでアプリ化した話
akidon0000
1
330
SRE チーム立ち上げ前に考えたこと・取り組んだこと / Considerations and Preparations Before Establishing an SRE Team
mackey0225
3
320
Folding Cheat Sheet #7
philipschwarz
PRO
0
150
CSC307 Lecture 10
javiergs
PRO
0
310
Trial
cairolibrary720
1
130
DynamoDB コスト最適化っぽいことの基本 with Terraform
kuro_kurorrr
2
250
Play Billing Library 7.0.0 変更点まとめ@potatotips#88
kako351
0
160
Featured
See All Featured
Fireside Chat
paigeccino
25
2.8k
Become a Pro
speakerdeck
PRO
15
4.8k
Build your cross-platform service in a week with App Engine
jlugia
227
17k
The MySQL Ecosystem @ GitHub 2015
samlambert
248
12k
Building Applications with DynamoDB
mza
89
5.8k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
149
45k
Designing with Data
zakiwarfel
96
5k
Navigating Team Friction
lara
181
13k
Building Your Own Lightsaber
phodgson
101
5.9k
Build The Right Thing And Hit Your Dates
maggiecrowley
28
2.2k
Debugging Ruby Performance
tmm1
71
11k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
353
29k
Transcript
Rustソースコードのざっくり とした歩き方 🦀 Takayuki Maeda / TaKO8Ki
• Rust committer (member of compiler contributors team and diagnostic
working group) • Rust Foundation 2023 Fellow Takayuki Maeda / TaKO8Ki @TaKO8Ki @TaKOBKi
テーマ
rustcのコードをほとんど読んだことないRustacean がコントリビュートするための ざっくり入門編
セットアップ
セットアップ 「Rust Compiler Development Guide」という素晴らしいドキュメントがある。 ref:
https://rustc-dev-guide.rust-lang.org
とりあえずgit cloneしてみる。 $ git clone https://github.com/rust-lang/rust.git $ cd rust
セットアップ rustリポジトリのbuildにはx.pyというツールを使います。これで標準ライブラリ含めて 丸っとbuildできます。 ref: https://rustc-dev-guide.rust-lang.org/building/bootstrapping.html
次にsetupしてみる。色々出てくるので最後compilerを選択する。 $ ./x.py setup
VSCodeユーザー向けに setting.jsonが自動的に追加される。 ref: Configuring rust-analyzer for rustc
その他サブコマンド (cargoと同じ感じ): $ ./x.py check $ ./x.py build $ ./x.py
test $ ./x.py fmt $ ./x.py clean
いよいよ、buildしてみる。 $ ./x.py build
buildしたcompilerをcargoやrustcで使う。 $ rustup toolchain link stage1 build/[your host]/stage1 $ cargo
+stage1 -vV $ rustc +stage1 -vV
準備が整ったのでとりあえずテストを実行してみる。 $ ./x.py test
セットアップ デバッグはどうやるのか? ref: https://rustc-dev-guide.rust-lang.org/compiler-debugging.html
backtraceが欲しい時は、 $ RUST_BACKTRACE=1 cargo +stage1 build
エラーの発生箇所が知りたい場合は、 $ RUSTFLAGS='-Z track-diagnostics' cargo +stage1 build
また、Rustではloggingにtracingというtokio organizationで開発されて いるcrateを使っている。 ref: Using tracing to debug the compiler
$ RUSTC_LOG=rustc_parse=debug cargo +stage1 build
セットアップ 基本は、修正 → UIテスト追加 → ./x.pyでテスト実行して壊れてないか確認 → プルリク の流れが多い。
コードを読んでみる
コードを読んでみる 全ては紹介しきれないので、まず、比較的優しい気がするparserを読んでみる。parse はparseがprefixとしてつくmethodやfunctionを目印に読んでいけばいい。 Rustのparserはトップダウンな再帰下降パーサー。 ref: https://rustc-dev-guide.rust-lang.org/overview.html#lexing-and-parsing
entry pointは、 - Parser::parse_crate_mod - Parser::parse_mod
parse_modを読み進めてみる。
parse_modを読み進めてみる。 上から順に見ていくと、 ここでloopでitemをparseしてそう
次にparse_itemに飛んでみる。
parse_item_を実行しているのでそっちに行ってみる。
parse_item_はこんな感じなのでそれっぽいparse_item_commonを見て みる。
parse_item_はこんな感じなのでそれっぽいparse_item_commonを見て みる。
まだコアの実装ぽいところにきて無さそうなので、parse_item_common_に ジャンプする。
まだコアの実装ぽいところにきて無さそうなので、parse_item_common_に ジャンプする。
なんかそれっぽくなってきた。 Parser::parse_item_commont_
なんかそれっぽくなってきた。 Parser::parse_item_commont_
拡大すると、なんか色々やってそうなmethodが見える。
ついにparse_item_kindに辿り着いた。
例えばここでenumをparseしてる。
せっかくなので、parse_item_enumも覗いてみる。
確かにmethodの下の方でコンマ区切りでEnum variantをparseしてそう。
では、ここで変更加えてbuildしてみる。 例えばこのエラーメッセージでリポジトリ 内を検索してみると
するとUIテスト用のファイルが見つかる。 tests/ui/structs-enums/issue-103869.rs
コードを読んでみる 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
では適当なdebug用のcrateを作ってmain.rsに下記をコピペしてみる。
試しにstage1コンパイラでbuildしてみると、 $ cargo +stage1 build
こういうエラーが得られる。
こういうエラーが得られる。 さっきparse_item_enumで見つけたエ ラーがある
試しにエラーメッセージを変更してみる。 perhaps you meant to use `struct` here foobar
再度buildする。 $ ./x.py build
もう一度デバッグ用のcrateをbuildしてみると、確かにエラーが変わってる。
これであなたもRustコントリビューター 🦀
コードを読んでみる rustc_parseの他にもRustリポジトリにはさまざまなcrateがある。 - rustc_ast_lowering - rustc_ast_passes - rustc_hir - rustc_hir_typeck
- rustc_borrowck などなど。
コードを読んでみる 例えば rustc_ast_lowering はrustc_parseで作ったASTをHIRにloweringするため のcrate。lowerがprefixなmethod、functionが目印。
rustc_ast_loweringのentry pointは、 rustc_ast_lowring::lower_to_hir
同じように覗いてみると、
同じように覗いてみると、 ast_indexごとにlower_nodeを呼んでそう
lower_nodeの実装は、
ここまでくるとなんかいけそう
同じように下に読み進めていけば良さそう
コードを読んでみる 基本はこんな感じで下記のようなcrateなら読める。 - rustc_resolve - rustc_hir - rustc_hir_typeck rustc_borrwckとかは割と複雑で難しい。
実際にissueに取り組 んでみる
実際にissueに取り組んでみる 今回は自分が過去に取り組んだ比較的シンプルなissueを参考に見てみます。 “consider dereferencing here” help doesn’t account for
operator precedence of the deref operator · Issue #105429 · rust-lang/rust
issueを見ると、下記のソースコードが与えられた時に、
このようなエラーが得られるとあります。(現時点では修正済み)
正しくないのはこの箇所です。
実際はこのようにdereferenceする必要があります。
検索したり-Zフラグを使ってエラーの発生箇所を特定してみると、 ref: rustc_trait_selection/src/traits/error_reporting/suggestions.rs#L778
検索したり-Zフラグを使ってエラーの発生箇所を特定してみると、 ref: rustc_trait_selection/src/traits/error_reporting/suggestions.rs#L778
やる必要があるのは、dereferenceする対象がmethodのreceiverの際に 特別なハンドリングをすること。 ref: rustc_trait_selection/src/traits/error_reporting/suggestions.rs#L778
何から始めたらいいか分からないと仮定してまず、spanに定義ジャンプしてみ る。 ref: rustc_trait_selection/src/traits/error_reporting/suggestions.rs#L778
ありました。これがspan。ObligationCauseのspanというfieldから取れるっ ぽい。 ref: rustc_trait_selection/src/traits/error_reporting/suggestions.rs
obligationはここでも使われてる。codeという概念があるらしい。 ref: rustc_trait_selection/src/traits/error_reporting/suggestions.rs
obligation.causeのなかにエラー発生箇所のspanなどの情報が詰められて そう?なことが分かる。 今回のissueではintoなのでargはありませ んが、これは引数のことっぽい。 ref: rustc_trait_selection/src/traits/error_reporting/suggestions.rs
obligation.causeのなかにエラー発生箇所のspanなどの情報が詰められて そう?なことが分かる。 また、hir_idというのが取れると、それがどう いうNodeかチェックできるっぽい ref: rustc_trait_selection/src/traits/error_reporting/suggestions.rs
このNode enumの定義を見てみる。 ref: rustc_trait_selection/src/traits/error_reporting/suggestions.rs
このNode enumの定義を見てみる。
このNode enumの定義を見てみる。
このNode enumの定義を見てみる。
さらにExpr structに飛んでみる。
Exprはkindを持ってるので、これでmethodのreceiverかどうか判別できる のでは?
でもarg_hir_idはあるが、対象のexprがmethod callで対象がその receiverかどうか判別できないとダメそう。 試しにFunctionArgumentObligationを見に行ってみる。
それっぽいのがあるので、いけそう!
ということでこの実装をcall_hir_idを使って修正してみる。
None
call_hir_idを元にexprがmethod callかど うか判別できた
あとはmethod callでかつ対象がそのreceiverの時だけ()で 囲ってdereferenceすればいい
実際にissueに取り組んでみる あとはUIテストを書いて全てのテストにパスすることを確認して、プルリクの完成 Suggest dereferencing receiver arguments properly by TaKO8Ki
· Pull Request #105595 · rust-lang/rust
まとめ
© Money Forward, Inc. まとめ • 基本は「Rust Compiler Development Guide」を読めば大体のことが分
かる。 • 下に下に掘り下げていけば割と読める。 • 分からないことはある程度推測しながら身につけていけば、全体像が見え なくても修正を加えたりできる。
We are hiring!
None