Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ruby 3 の型解析に向けた計画

Ruby 3 の型解析に向けた計画

Yusuke Endoh

June 10, 2019
Tweet

More Decks by Yusuke Endoh

Other Decks in Programming

Transcript

  1. 1. 型シグネチャフォーマット •Rubyコードの型情報を示すもの class Array[A] include Enumerable def []: (Integer)

    -> A def []=: (Integer,A) -> A def each: { (A) -> void } -> self ... end interface generics union type option type any type Proposal: ruby-signature 7
  2. 2. 型シグネチャなし型検査 •型エラーの可能性を指摘する解析器 •アプリの型シグネチャが無くても動作する • false positive は許容する def foo(s)

    s.gsuub!(//, "") s + 42 end foo("foo") NoMethodError? TypeError? Proposals: • mruby-meta-circular • 型プロファイラ 8
  3. Ruby 3の静的解析の図 Library code type signature Sorbet Steep RDL Type

    error warnings Application code mmc Type Profiler Type error warnings type signature 11
  4. 型エラーの指摘 •NoMethodErrorやTypeErrorの可能性を示す def foo(n) if n < 10 n.timees {|x|

    } end end foo(42) Type Profiler t.rb:3: [error] undefined method: Integer#timees Typo 17
  5. 型プロファイラの動作イメージ •Rubyコードを「型レベル」で実行する 普通のインタプリタ def foo(n) n.to_s end foo(42) Calls w/

    42 Returns "42" 型プロファイラ def foo(n) n.to_s end foo(42) Calls w/ Integer Returns String Object#foo :: (Integer) -> String 19
  6. デモ:オーバーロードの例 def my_to_s(x) x.to_s end my_to_s(42) my_to_s("STR") my_to_s(:sym) Type Profiler

    Object#my_to_s :: (Integer) -> String Object#my_to_s :: (String) -> String Object#my_to_s :: (Symbol) -> String 20
  7. デモ:再帰関数の例 def fib(n) if n > 1 fib(n-1) + fib(n-2)

    else n end end fib(10000) Type Profiler Object#fib :: (Integer) -> Integer 21
  8. デモ:ユーザ定義クラスの例 class Foo end class Bar def make_foo Foo.new end

    end Bar.new.make_foo Type Profiler Bar#make_foo :: () -> Foo 22
  9. 型プロファイラと分岐 •実行を「フォーク」する def foo(n) if n < 10 n else

    "error" end end foo(42) Fork! イマココ n<10 の真偽は わからない Returns Integer Returns String Object#foo :: (Integer) -> (Integer | String) 23
  10. 解析アルゴリズム •環境:各変数がとりうる型 •{ x: Integer or String, y: Integer }

    とか •行ごとの「環境」を更新していく • 正確に言うとYARVのバイトコードごと •「環境」が更新されなくなったら終わり 28
  11. 解析の例 1: def foo(a) 2: if a < 10 3:

    b = 42 4: else 5: b = "str" 6: end 7: c = b 8: c 9: end 10: 11: ret = foo(42) 行番号 a b c 1 ∅ ∅ ∅ 2 ∅ ∅ ∅ 3 ∅ ∅ ∅ 4 - - - 5 ∅ ∅ ∅ 6 - 7 ∅ ∅ ∅ 8 ∅ ∅ ∅ 行番号 a b c 1 { Int } ∅ ∅ 2 ∅ ∅ ∅ 3 ∅ ∅ ∅ 4 - - - 5 ∅ ∅ ∅ 6 - 7 ∅ ∅ ∅ 8 ∅ ∅ ∅ 行番号 a b c 1 { Int } ∅ ∅ 2 { Int } ∅ ∅ 3 ∅ ∅ ∅ 4 - - - 5 ∅ ∅ ∅ 6 - 7 ∅ ∅ ∅ 8 ∅ ∅ ∅ 行番号 a b c 1 { Int } ∅ ∅ 2 { Int } ∅ ∅ 3 { Int } ∅ ∅ 4 - - - 5 { Int } ∅ ∅ 6 - 7 ∅ ∅ ∅ 8 ∅ ∅ ∅ 行番号 a b c 1 { Int } ∅ ∅ 2 { Int } ∅ ∅ 3 { Int } ∅ ∅ 4 - - - 5 { Int } ∅ ∅ 6 - 7 { Int } { Int } ∅ 8 ∅ ∅ ∅ 行番号 a b c 1 { Int } ∅ ∅ 2 { Int } ∅ ∅ 3 { Int } ∅ ∅ 4 - - - 5 { Int } ∅ ∅ 6 - 7 { Int } { Int } ∅ 8 ∅ ∅ ∅ 行番号 a b c 1 { Int } ∅ ∅ 2 { Int } ∅ ∅ 3 { Int } ∅ ∅ 4 - - - 5 { Int } ∅ ∅ 6 - 7 { Int } { Int, Str } ∅ 8 ∅ ∅ ∅ 行番号 a b c 1 { Int } ∅ ∅ 2 { Int } ∅ ∅ 3 { Int } ∅ ∅ 4 - - - 5 { Int } ∅ ∅ 6 - 7 { Int } { Int, Str } ∅ 8 ∅ ∅ ∅ 行番号 a b c 1 { Int } ∅ ∅ 2 { Int } ∅ ∅ 3 { Int } ∅ ∅ 4 - - - 5 { Int } ∅ ∅ 6 - 7 { Int } { Int, Str } ∅ 8 { Int } { Int, Str } { Int, Str } Object#foo :: (Int) -> (Int|Str) 29
  12. 他の問題 •嘘の警告・推定が出ることがある •原理的に扱えない言語機能がある • sendメソッド・特異クラス 30 # b: Integer or

    String c = b # c: Integer or String # 「bとcの型は同じ」という条件が消えるので b + c # 「Integer + String の可能性あり!」
  13. 関連研究 •mruby-meta-circular (Hideki Miura) •型プロファイラの元ネタ •HPC Ruby (Koichi Nakamura) •

    抽象解釈でRubyからCへ変換(HPC向け) •pytype (Google's unofficial project) • 型解析のための抽象解釈器 34
  14. 謝辞 •Hideki Miura •Matz, Akr, Ko1 •PPL paper co-authors •

    Soutaro Matsumoto • Katsuhiro Ueno • Eijiro Sumii •Stripe team & Jeff Foster •And many people 35