Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
TypeProf進捗 Yusuke Endoh (@mame) RubyKaigi 2024 followup
Slide 2
Slide 2 text
復習: TypeProf • 型注釈を必須としない Rubyの型解析・エディタ支援ツール • データフロー解析に基づく • RBSがあれば読み込む • RubyKaigiの発表:貢献を呼び掛けた • "Good first issues of TypeProf" • パッチの書き方、テストの仕方などを説明した 5.ti| 1 + "str" TypeError Do you mean: 5 .times
Slide 3
Slide 3 text
みんなありがとう • 100+ pull requests 0 2 4 6 8 10 12 14 16 18 20 PR数 ※数え間違えてたらごめんなさい
Slide 4
Slide 4 text
進捗 • ruby/ruby の lib/**/*.rb の全ファイルが ほぼ 解析できた • ただし • lib/ruby_vm/rjitだけは除く(パターンマッチ……) • 解析時間は要改善(850ファイルで8分、1ファイル平均0.6秒) • lib/reline/line_editor.rb 1つが数分くらいかかるので要調査 • ファイルごとに解析してる(相互作用によるバグは絶対まだまだある) • false positiveも気にしてない(これから潰し方を考えていく)
Slide 5
Slide 5 text
むずかしくて面白い問題 • 次のコードを解析するとTypeProfが無限ループ • lib/resolv.rbから簡略化して得た例 @a = @b[0] @b = "x" + @a
Slide 6
Slide 6 text
無限ループの仕組み (1) • 解析の初期状態 • @a: untyped • @b: untyped @a = @b[0] @b = "x" + @a
Slide 7
Slide 7 text
無限ループの仕組み (2) • 現在の状態 • @a: untyped, @b: untyped • 1行目の解析 • レシーバの@bはuntyped • @aはuntypedのまま • 新しい状態 • @a: untyped, @b: untyped @a = @b[0] @b = "x" + @a
Slide 8
Slide 8 text
無限ループの仕組み (2) • 現在の状態 • @a: untyped, @b: untyped • 2行目の解析 • String#+: (String) -> String • @bはuntyped(何にでもマッチ)なので@aはStringになる • 新しい状態 • @a: untyped, @b: String @a = @b[0] @b = "x" + @a
Slide 9
Slide 9 text
無限ループの仕組み (4) • 現在の状態 • @a: untyped, @b: String • 1行目の(再)解析 • レシーバの型が変わったので再解析が発生する • String#[]: (Integer) -> String? • @aはString?になる • 新しい状態 • @a: String?, @b: String @a = @b[0] @b = "x" + @a
Slide 10
Slide 10 text
無限ループの仕組み (5) • 現在の状態 • @a: String?, @b: String • 2行目の(再)解析 • 引数の型が変わったので再解析が発生する • String#+: (String) -> String • @aはString? なのでマッチしない!ので@bはuntypedになる • 新しい状態 • @a: String?, @b: untyped @a = @b[0] @b = "x" + @a
Slide 11
Slide 11 text
無限ループの仕組み (6) • 現在の状態 • @a: String?, @b: untyped • 1行目の(再)解析 • レシーバの型が変わったので再解析が発生する • レシーバの@bがuntypedなので、@aはuntypedにもどる • 新しい状態 • @a: untyped, @b: untyped → 初期状態! @a = @b[0] @b = "x" + @a
Slide 12
Slide 12 text
無限ループの仕組み: まとめ • 解析状態の更新がループしてしまっていた • @a: untyped, @b: untyped • @a: untyped, @b: String • @a: String?, @b: String • @a: String?, @b: untyped • @a: untyped, @b: untyped
Slide 13
Slide 13 text
暫定対応:引数マッチの処理を変更した • String#+: (String) -> String に String? を渡す場合 • 旧:String? はマッチしないのでuntypedを返す • 新:String? は String にマッチすることにする • 警告は出す(TODO) • これで一旦 lib/**/*.rb を全パスした(rjit除く)
Slide 14
Slide 14 text
完全ではなかった • この資料を作りながら考えてたら 刺さるシナリオが作れてしまった ## update: test.rbs class C def foo: (C) -> C def bar: -> Integer end ## update: test.rb def check c = C.new @a = @b.bar @b = c.foo(@a) end
Slide 15
Slide 15 text
問題の整理 • 一度マッチしたメソッド呼び出しは外れてほしくない • 考えられる直し方 • 保守的な案:untypedは何にもマッチしないことにする • "x" + untyped が String にならなくなる • TypeScript の any から大きく違う意味になる • 雑な案:引数の数さえあってれば常にマッチすることにする • "x" + 1 は String を返すと推論する(型エラーは出す) • 1 + 1 が (Complex | Rational | Integer | Float) になるのはちょっと不幸 • 鋭意検討中です
Slide 16
Slide 16 text
まとまらないまとめ • TypeProf鋭意開発中です • 進捗と現状 • Rubyの全文法対応までたぶんあと少し • いろんなコードに適用して問題洗い出し・対応中 • Ruby 3.4.0にはTypeProf v2をバンドルしたい • パターンマッチ構文のサポートと TypeProf v1の互換インターフェイスを作ったら最低限いけるはず