はまっているので現実逃避

yarv2llvmはブロック呼び出しを作っています。ブロックを伴ったメソッド呼び出しは、引数に呼び出し元のフレームへのポインタとブロックの関数へのポインタ(ブロックは関数で実現します)がこっそり引数として追加されます。多分ここで関数の定義と呼び出しで型が合わないのが悪いのだと思いますが、llvm様が気に入らないようです。

assertion "(NumParams == FTy->getNumParams() || (FTy->isVarArg() && NumParams > FTy->getNumParams())) && 
"Calling a function with bad signature!"" failed: file "Instructions.cpp", line 289

ところが、見る限り定義と呼び出しで引数の型があっているみたいです。どうしたものかちょっと困っています。せめてどの引数が悪いか教えてくれてもいいじゃんって思います。

そういうことで、実作業ははまっているのですが、出来るか判らないのですが、ちょっとアイデアを思いつきました。CyanのASTがFirst Classであるって話がヒントになっています。

はじめにyarv2llvmの型推論の概要を説明します。

  1. yarv2llvmは型推論を行うために、コンパイルするプログラムのあらゆるデータについて型情報を保持するオブジェクト(RubyTypeオブジェクト)を割り当てています。あらゆるデータとは変数、リテラルはもちろん、計算式の途中結果やメソッドの引数や戻り値などにも割り当てます。
  2. RubyTypeオブジェクトはこのオブジェクトと同じ型だよっていうリンクを持っています。このリンクを適時繋げて行きます。例えばopt_plus命令では、実行に係る3つのデータ(2つの引数と計算結果)のRubyTypeオブジェクトそれぞれに同じ型というリンクをつなげます。
  3. リテラルや返値や引数の型が判っているメソッドなどから自明な型を決定します。自明な型が決まれば、同じだよってつなげたリンクすべてを同じ型にします。
  4. 同じ型だよってなっているけど、違う型の自明な型が現れたら型矛盾なんでプログラムを直す必要があります。

あと、Common Lispではコンパイル時にCommon Lispのプログラムを実行するeval-whenという機能がありますが、これをyarv2llvmに取り入れます。

そして、eval-when相当の機能で実行するRubyプログラムからRubyTypeオブジェクトをアクセスできるようにします。

こうすると、何がうれしいかというと型推論のポリシーをユーザが定義できるのではないかなって思うわけです。がちがちに型を厳しくして動的な機能を一切許さないようにすることもできるし、変数内にはVALUE型のデータを常に入れておいて適時必要なときに型変換するようにして動的な機能が使い放題にする(でも遅い)、というカスタマイズがプログラム毎にできるんじゃないかなと思います。