型変数をどう表現するか
WebAssemblyのValidationを実装しています。初めてで拙いながらも実装方法を考えているところです。WebAssemblyの命令のうち、一部はpolymorphicなものがあって、value-polymorphicな命令とstack-polymorphicな命令があります。stack-polymorphicな命令に関しては以下でとりあげました。
今回はもう一つのvalue-polymorphicな命令がテーマです。こちらは割と馴染みのある感じのpolymorphismという感じで、要するにジェネリクスですね。例えば、select命令では以下のようになっています。
この場合、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にも変更が必要ですが、それは今回は省きます。これで一回書いてみましょう。