型変数をどう表現するか

ironoir.hatenablog.com

WebAssemblyのValidationを実装しています。初めてで拙いながらも実装方法を考えているところです。WebAssemblyの命令のうち、一部はpolymorphicなものがあって、value-polymorphicな命令とstack-polymorphicな命令があります。stack-polymorphicな命令に関しては以下でとりあげました。

ironoir.hatenablog.com

今回はもう一つのvalue-polymorphicな命令がテーマです。こちらは割と馴染みのある感じのpolymorphismという感じで、要するにジェネリクスですね。例えば、select命令では以下のようになっています。

f:id:ironoir:20210304125628p:plain

この場合、tに(全体がvalidになるように)任意の型が入ります。最初はもともとある型定義にAnyを付け足して、これで凌ごうと思ったんですが、これだと上記のselect命令だと、「tには同じ型が入るんですよ」という情報が抜け落ちてしまいます。

enum ValType {
    Any, // add
    I32,
    I64, 
    F32,
    F64,
}
// instr_tp!は今回型宣言を簡単に書くためのマクロです
instr_tp!(Any Any I32 -> Any)

// でもこれだと
// instr_tp!(I64 F32 I32 -> F64)
// とかでもOKになってしまう

せっかくなのでちゃんと作るとなるとどうなるんだろう、と考え始めました(一方で、polymorphicな命令は全体の中では少数なので、おしごとだったらアドホックなコードを書いて終わらせるやろな、とも思いつつ)。

enum ValType {
    I32, I64, F32, F64,
}

type ResultType = Vec<ValType>;

type FuncType = (ResultType, ResultType);

もともと、関数型FuncTypeの定義は上記のように作っていました。これはWebAssemblyの仕様書に忠実な実装だと思います。ここに型変数を導入する、ということですね。

うーん、ざっくり思いついたのだと、こんな感じですかね?

enum ValType {
    I32, I64, F32, F64,
    TypeVal(TypeValIdx),
}

type ResultType = Vec<ValType>;

type TypeValIdx = u32;
type FuncType = (Vec<TypeValIdx>, ResultType, ResultType);

関数単位でジェネリクスを持てればいい(select命令が例)ので、関数に型変数のVecを持って、それをValTypeの中に足す、ということでしょうか。インデックスはu32ですがなんでもいいです。実際にはここにstack-polymorphicな命令への考慮も必要になってくるので、ResultTypeにも変更が必要ですが、それは今回は省きます。これで一回書いてみましょう。