本エントリは Swift Tweets 2017 Summer でのツイート1をまとめ、加筆修正したものです。内容は 2017/07/22 時点でのものであることにご注意ください。
それでは、『実践Swiftコンパイラ』というタイトルで発表します。よろしくお願いします。 #swtws pic.twitter.com/Lx6pbZlLfO
— Rintaro Ishizaki (@rintaro) July 22, 2017
Swift がオープンソース化されてしばらく経ちます。コンパイラにコントリビュートしたくても、どこから手をつけていいのやらと思ってませんか?
コンパイラのコードを修正していくときに、具体的に何を手がかりにすれば良いのか、実際のバグを修正しながらご紹介します。
僕がコントリビュート始めたのは2016年の3月です。これが僕の初めてのPR。
日付に注目ください。完全に try! Swift 2016 きっかけでした。
https://github.com/apple/swift/pull/1543
try! Swift のプレゼンテーション 『Dive into Swift Ecosystem』 や 『Contributing to Open Source Swift』 に影響されまくり、 Jesse に Q&A セッションで「どう思います?」って聞いたら「PR投げちゃいなよ!」って言われ、翌日には PR 出してました。
Linux上でのコンパイル警告つぶすだけの簡単な PR でしたが、サクッとマージされ、一人で「ぉおおー」ってなってました。
というわけで、「ぉおおー」なってみたい人のために、実際どんな感じで修正していくのか説明していきます。
ちなみに C++ 経験なくてもなんとかなります。実際のところ、僕が10行以上の C++ コード書いたのはこのプロジェクトが始めてです!
1⃣ 環境構築
省略しますが、 別記事に環境構築方法をアップしているので、よかったら見てください。初回ビルドまで済ませば、この内容を実際に試せます。
2⃣ 何をするのか?
コンパイラの実コードに手を付ける修正で、わりと初心者向けのジャンルに「診断メッセージの改善」っていうのがあります。 DiagnosticQoI とか単に QoI2 って呼ばれてます。
同テーマのIssue:
https://bugs.swift.org/issues/?jql=labels%20%3D%20%22DiagnosticsQoI%22
同テーマのマージ済みプルリクエスト:
https://github.com/apple/swift/pulls?q=is%3Apr+QoI+is%3Amerged
例えば、インタンスに .init
を呼ぶと発生するエラーがあります。この [Fix] ボタンを押すと、
こうならなければいけないのに・・・
実際にはこんなことになってしまいます。 init
が type(of: )
で囲まれてしまっていますね。
実はこういうエラーは、メッセージだけではなく [Fix]
の内容も Swift のコンパイラが出しているものなのです。つまり私たちが直せるものです!これを修正し、改善するのが DiagnosticsQoI
です。
3⃣ 修正!
まずはこのエラーがどこで発行されているかを調べます。
エラーメッセージで grep してみましょう!
$ git grep "is a member of the type"
一行上にエラーの ID っぽいものが見つかったので、それをまた grep!
$ git grep "init_not_instance_member"
見つかりました。 何も知らなくても、なにやら fixItRng
を "type(of: "
と ")"
で囲んでいるというのくらいは読み取れると思います。
ほかにも:
-
fixItRng
はSourceRange
型で、ソース上の範囲を示している - 現在の挙動から、これは
foo.init
のinit
の部分の範囲を示している
というのもなんとなくわかると思います。そこまでわかったら周りのソース見てみましょう。
- foo の部分はどの変数に入っているのかな? →
baseExpr
っていうのがある! - どうやって そのソース範囲を取得するのかな? →
getSourceRange()
っぽい!
という感じでなんとなく分かることも多いです。
結果こんな感じになりました。一行修正しただけですね。
4⃣ テスト!
$ utils/build-script -Rt
でビルドとテストを実行して、何が起こるか見てみましょう。
エラーになりました。どうも元々のテストケースが間違っていたみたいです😢
ということは、修正だけすればOKですね。テストを追加する必要はなさそうです。
テストについては、 別エントリにも書いたので参考にしてください。
修正の結果はこんな感じになります。
再テストしたら、通るようになりました。👏
あとは、PR投げるだけ...
ちょっとまって! 本当にこれでよい?
これを Optional
の foo?.init()
に適用したら。。。
こんなことになってしまいます。 Optional<Foo>
に init(x:)
は存在しないためです。
これに対する対応としては
-
baseExpr
がOptional
チェーンだったらエラーメッセージのみを出し、 Fix-it を出さない -
foo.map({ type(of: $0) })?.init(x: 12)
になるようにする
などですが、決めかねます。
こういうときは、少なくとも現状よりはマシになっているのを盾にとりあえずPR出しちゃいましょう。そこに現状の問題点記載しておけば誰かがアドバイスくれるはず。
5⃣ PRの出し方
まずは、GitHub の自分のフォークリポジトリに push ですね。
ブランチ作って、コミットして、 push する。まあ普通です。
$ git checkout -b fixit-init-instance
M lib/Sema/CSDiag.cpp
M test/expr/postfix/dot/init_ref_delegation.swift
Switched to a new branch 'fixit-init-instance'
$ git add lib/Sema/CSDiag.cpp test/expr/postfix/dot/init_ref_delegation.swift
$ git commit -F - <<EOF
> [QoI] Fix misplaced fix-it for calling initializer on instances
>
> - Fixed the position for fix-it
> - Updated existing test cases
> EOF
[fixit-init-instance 28d1093f35] [QoI] Fix misplaced fix-it for calling initializer on instances
2 files changed, 10 insertions(+), 10 deletions(-)
$ git push private
Enter passphrase for key '/Users/rintaro/.ssh/id_rsa':
Counting objects: 10, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (10/10), done.
Writing objects: 100% (10/10), 945 bytes | 0 bytes/s, done.
Total 10 (delta 8), reused 0 (delta 0)
remote: Resolving deltas: 100% (8/8), completed with 8 local objects.
To github.com:rintaro/swift.git
* [new branch] fixit-init-instance -> fixit-init-instance
$
Swift プロジェクトでは、コミットメッセージはほぼ自由で、あまり体裁にこだわる必要はありません。
[カテゴリ] お題
...説明...
くらいです。簡単なコミットだったら説明なくても大丈夫。
最終的な PR 用ブランチはこんな感じになりました。
PR は必ず master ブランチに。
全ての変更はまず master ブランチにマージされます。 Swift4.0 に必要なら master から 必要な部分だけ swift-4.0-branch に cherry-pick されます。なので、 まずは master に PR 出しましょう。
適当な英語でも意味さえ通じれば誰も気にしない。
PRのコメントですが、意味さえ通じればなんとかなります。今回のような修正だったらエラー対象のコード書いておくだけでも大丈夫でしょう。
ちなみに master ブランチでは Label や Assignee などは必要ありません。担当つけなくても誰かが拾って、なんとかしてくれます。
6⃣ プルリクエストのテスト
テストはそれなりに時間かかることもあり、コミット権持っているユーザーだけが起動できます。
だれかが swift-ci 様に Please test してくれるのを待ちましょう。
以上です。地味ですが、こういう Fix-it の修正は利用者の利便性に大きく関わってくるため、ひじょーに重要なのです。
ニッチ過ぎる!などと思わず、見つけたら積極的に直してPR投げてみてください。
コードリーディング中に typo 見つけたらそれだけでも PR 投げてみてください。積極的にマージされます。
https://github.com/apple/swift/pulls?q=is%3Apr+gardening+is%3Aclosed
バグ見つけたけど直し方が分からない場合は是非バグ報告してください。バグ報告も貴重なコントリビュートです!
https://bugs.swift.org
ちなみにここで修正した件も既にIssueトラッカーに上がっています。自分アサインした人がなかなか修正してくれないので止まっちゃってる案件。
https://bugs.swift.org/browse/SR-3245
最後に、コントリビュートへのモチベーションあげるプレゼンテーションを2つご紹介しておきます。
『Contributing to Swift: From Proposal to Shipped』Russ Bishop
『Contributing to the Swift compiler』 Ayaka Nonaka
なにか分からないことがあったら @mono0926 さん主宰の Discord にいるので、遠慮無く質問ください。
try! Swift compiler
-
実際のツイートは2017/7/22 #swtws Swift Tweets 2017 Summer - Togetterまとめ をご覧ください。 ↩
-
Quality of Implementation の略で、診断に限らない用語だと思うのですが、なぜかこの文脈以外では使われていないです。 ↩