青木です。
訳あって ML の過去ログを発掘しているのですが、[ruby-dev:13152]
に出てきたスクリプトで別の問題が起こっていることを見付けました。
class C
$tmp = lambda {
def m() puts "OK" end
}
end
$tmp.call
C.new.m
1.6.8 と CVS HEAD でこのプログラムを実行すると次のようにエラーに
なります。
~ % ruby t
t:7: private method `m' called for #<C:0x40270ccc> (NoMethodError)
1.6.[0-7] は OK でしたが、これはトップレベルのスコープが (偶然)
SCOPE_PUBLIC だったからのようです。その証拠に CVS HEAD でも次の
ように変えるとエラーになりません。
class C
$tmp = lambda {
def m() puts "OK" end
}
end
class D
$tmp.call
end
C.new.m
1.6.8 から private を判定するルーチンが変わり、同時にトップレベル
の vmode が SCOPE_PRIVATE になったため、このバグが発覚したようです。
いちおうパッチを付けます。
scope_vmodeって無条件に書き戻しちゃっていいものでしょうか?
-------------------------------------------------------------------
青木峰郎
Index: eval.c
===================================================================
RCS file: /home/aamine/var/cvs/ruby/ruby/eval.c,v
retrieving revision 1.462
diff -u -p -r1.462 eval.c
--- eval.c 17 Jun 2003 03:12:28 -0000 1.462
+++ eval.c 18 Jun 2003 03:53:42 -0000
@@ -4014,6 +4014,7 @@ rb_yield_0(val, self, klass, pcall, aval
volatile VALUE old_wrapper;
struct BLOCK * volatile block;
struct SCOPE * volatile old_scope;
+ int old_vmode;
struct FRAME frame;
NODE *cnode = ruby_current_node;
int state;
@@ -4035,6 +4036,8 @@ rb_yield_0(val, self, klass, pcall, aval
ruby_wrapper = block->wrapper;
old_scope = ruby_scope;
ruby_scope = block->scope;
+ old_vmode = scope_vmode;
+ scope_vmode = block->vmode;
ruby_block = block->prev;
if (block->flags & BLOCK_D_SCOPE) {
/* put place holder for dynamic (in-block) local variables */
@@ -4154,6 +4157,7 @@ rb_yield_0(val, self, klass, pcall, aval
if (ruby_scope->flags & SCOPE_DONT_RECYCLE)
scope_dup(old_scope);
ruby_scope = old_scope;
+ scope_vmode = old_vmode;
ruby_current_node = cnode;
if (state) {
if (!block->tag) {