Moose metaclass compatibility is too complex!

Mooseのmetaclass compatibilityのルールがとんでもなく複雑だということがわかったのでメモしておく。
コード例:

#!perl
use strict;
use warnings;
use Test::More tests => 4;
use Moose::Util qw(does_role);
{
    package FooTrait;
    use Moose::Role;

    package BarTrait;
    use Moose::Role;

    package BaseClass;
    use Moose -traits => qw(FooTrait);

    package SubClass;
    use Moose -traits => qw(BarTrait);

    extends qw(BaseClass);
}
ok does_role(BaseClass->meta, 'FooTrait'), ' BaseClass->meta->does("FooTrait")';
ok!does_role(BaseClass->meta, 'BarTrait'), '!BaseClass->meta->does("BarTrait")';

ok does_role(SubClass->meta,  'FooTrait'), 'SubClass->meta->does("FooTrait")';
ok does_role(SubClass->meta,  'BarTrait'), 'SubClass->meta->does("BarTrait")';
__END__

まず基本ルールとして,クラスに階層関係があるBaseClass,SubClassがあるとき,SubClass->meta is-a BaseClass->metaでなければならない。これがmetaclass compatibilityというルールで,Class::MOPで説明されている。

さて,上記のコードではBaseClassに-traitsを指定しているが,これはBaseClass->metaにroleを当てる*1ことになるので,BaseClass->meta->does('FooTrait')となる。基本ルールを適用すると,その結果当然SubClass->meta->does('FooTrait')も期待できる。
ここで,SubClassに-traitsを指定する,つまりSubClass->metaにroleを当てるとどうなるか。SubClass->metaはBaseClass->metaを継承しつつdoes('BarTraits')というような代物になるはずである。実際,Mooseでは上記のテストコードは問題なく通る。すばらしい。

問題はその実装だ。useディレクティブがコンパイル時に行われ,extends()関数が実行時に呼ばれる以上,SubClass->metaにroleを当てた後にBaseClass=>SubClass間のクラス階層が構築されるのだ。このときextends()は基本ルールが成立しているかどうかをチェックするのだが,SubClassにはroleが当てられているのでmetaclass compatibilityに適合しない!そこでそれをfixするためにBaseClass->metaに当てられているroleを解析して…というところまで理解したが,そこで力尽きた。
だが,このmetaclass compatibility resolutionをMouseに移植しないとuse Mouse -traits => ...を実装できないのだ。これができたら0.41のリリースということになるだろう。

(追記)
実装できた。これで0.41と行きたいところだが,-traitsを使うと5.6.2でSEGVが起きる。とりあえず5.6.2でのテストをスキップして0.40_08にした。

*1:この「当てる」は「パッチを当てる」の「当てる」と同じ意味である