Gauche > Archives > 2016/03/19

2016/03/19 07:08:55 UTCshiro
#
wilikiのGauche:Bugsに報告されたrequireの問題を直してたらコンパイラのバグを見つけた。通常の使用では問題にならないんだけど。
#
pass4で、クローズしてる変数のないlambdaはトップレベルにliftされて、gensymされた名前に束縛される。そのトップレベルの束縛が挿入されるのは、元々コンパイラを起動したトップレベルモジュールだ。つまり(define-module foo ...)というフォームをコンパイルしていて、その中でlambdaがliftされたとしても、それはfooというモジュール中ではなく、define-moduleの外側のモジュールで束縛される。
#
名前そのものはgensymされているので決して衝突することはないから、どこのモジュールに束縛されようがこれまで問題が表面化することはなかった。ただ、requireの問題修正のために「変更不可なモジュール」というのを導入したら、この問題が見えるようになった。liftされた束縛を挿入する先が変更不可モジュールだとエラーになる。
#
直感的には、(define-module foo ...) の中でliftされたなら、fooに束縛が挿入されるのが自然だ。ところがdefine-moduleやwith-moduleはpass1の時点で消費されちゃっててpass4には残ってない。pass1の段階でグローバル変数参照に全てモジュール情報を付加するので以降は必要ない…はずだったんだが、pass4で「新たなグローバル(トップレベル)変数」が導入されることになって問題となったわけだ。
#
モジュール情報をIFormに保持しておくという手もあるけど、with-moduleがネストしたりしてると「liftしたlambdaの束縛の挿入先」というのはあんまり自明ではない。どうせgensymしてて衝突の心配はないんだから、lift用の無名モジュールでも別に作ってそこに入れようか。