Project

General

Profile

Actions

Backport #5731

closed

enum_for を使うと method_missing にブロックが渡されない

Added by tommy (Masahiro Tomita) over 12 years ago. Updated almost 8 years ago.

Status:
Rejected
Assignee:
-
[ruby-dev:44961]

Description

次のスクリプトを 1.9.3 で実行すると enum_for の方は block が nil になります。
1.8.7 では両方とも block が渡されました。


class A
def method_missing(name, *args, &block)
p block
end
end

a = A.new
a.hoge{|l| p l} # ブロックが渡される
a.enum_for(:hoge).each{|l| p l} # ブロックが渡されない

% /usr/local/ruby187/bin/ruby -v a.rb
ruby 1.8.7 (2011-06-30 patchlevel 352) [i686-linux]
#Proc:0xb76dbb60@a.rb:9
#Proc:0xb76db8e0@a.rb:10

% ruby -v a.rb
ruby 1.9.3p0 (2011-10-30) [i686-linux]
#Proc:0x8829080@a.rb:9
nil

使い方が間違ってるだけだったらすいません

Updated by ktsj (Kazuki Tsujimoto) over 12 years ago

=begin
今のmethod_missing関数の実装はpassed_blockを無条件に0クリアするようになっています。

同関数ではmethod_missingメソッドを呼び出す前に色々と処理を行っており
その際にraiseされる可能性があるので0クリアしておくことは必要ですが、
前処理が終わった時点でpassed_blockを再設定しておかないといけないという話ではないかと思います。

以下のパッチでどうでしょうか。

diff --git a/vm_eval.c b/vm_eval.c
index 44edf6f..d653e4e 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -563,6 +563,7 @@ method_missing(VALUE obj, ID id, int argc, const VALUE *argv, int call_status)
{
VALUE *nargv, result, argv_ary = 0;
rb_thread_t *th = GET_THREAD();

  • const rb_block_t *blockptr = th->passed_block;

    th->method_missing_reason = call_status;
    th->passed_block = 0;
    @@ -589,6 +590,7 @@ method_missing(VALUE obj, ID id, int argc, const VALUE *argv, int call_status)
    if (rb_method_basic_definition_p(CLASS_OF(obj) , idMethodMissing)) {
    raise_method_missing(th, argc+1, nargv, obj, call_status | NOEX_MISSING);
    }

  • th->passed_block = blockptr;
    result = rb_funcall2(obj, idMethodMissing, argc + 1, nargv);
    if (argv_ary) rb_ary_clear(argv_ary);
    return result;
    =end

Updated by matz (Yukihiro Matsumoto) over 12 years ago

  • ruby -v changed from ruby 1.9.3p0 (2011-10-30) [i686-linux] to -

まつもと ゆきひろです

In message "Re: [ruby-dev:45003] [ruby-trunk - Bug #5731] enum_for を使うと method_missing にブロックが渡されない"
on Sun, 18 Dec 2011 00:33:10 +0900, Kazuki Tsujimoto writes:

|=begin
|今のmethod_missing関数の実装はpassed_blockを無条件に0クリアするようになっています。
|
|同関数ではmethod_missingメソッドを呼び出す前に色々と処理を行っており
|その際にraiseされる可能性があるので0クリアしておくことは必要ですが、
|前処理が終わった時点でpassed_blockを再設定しておかないといけないという話ではないかと思います。
|
|以下のパッチでどうでしょうか。

このパッチを確認してくださる方はいらっしゃいませんか?
問題が内容なら積極的に取り込みたいのですが。

Updated by shiba (satoshi shiba) over 12 years ago

芝と申します。

パッチが正しいかどうかは分かりませんが、passing_block の設定が抜けてる関数は method_missing 以外にもあるので、一緒に対処してはどうでしょうか。

例えば、vm_call0 での passing_block の設定忘れは次のコードで確認できます。

問題となるコード(vm_call0 のほう)

missing.rb

def respond_to_missing?(*args)
true
end

def method_missing(mid, *args)
yield
end

m = method(:call_missing)
m.call(){ puts "passing block ok" }

追加パッチ

Index: vm_eval.c

--- vm_eval.c (revision 34071)
+++ vm_eval.c (working copy)
@@ -118,6 +118,7 @@

    RB_GC_GUARD(new_args);
    rb_ary_unshift(new_args, ID2SYM(id));
  •   th->passed_block = blockptr;
      return rb_funcall2(recv, idMethodMissing,
                         argc+1, RARRAY_PTR(new_args));
     }
    

Index: vm_insnhelper.c

--- vm_insnhelper.c (revision 34071)
+++ vm_insnhelper.c (working copy)
@@ -555,6 +555,7 @@
argv[0] = ID2SYM(me->def->original_id);
MEMCPY(argv+1, cfp->sp - num, VALUE, num);
cfp->sp += - num - 1;

  •            th->passed_block = blockptr;
              val = rb_funcall2(recv, rb_intern("method_missing"), num+1, argv);
              break;
            }
    
Actions #4

Updated by nobu (Nobuyoshi Nakada) about 12 years ago

  • Status changed from Open to Closed
  • % Done changed from 0 to 100

This issue was solved with changeset r34399.
Masahiro, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


  • vm_eval.c (vm_call0): should pass block to enumerators. patched
    by Kazuki Tsujimoto. [ruby-dev:44961][Bug #5731]
  • vm_eval.c (method_missing), vm_insnhelper.c (vm_call_method):
    ditto. patched by satoshi shiba.
Actions #5

Updated by nobu (Nobuyoshi Nakada) about 12 years ago

  • Tracker changed from Bug to Backport
  • Project changed from Ruby master to Backport193
  • Status changed from Closed to Open
Actions #6

Updated by kosaki (Motohiro KOSAKI) about 12 years ago

  • Status changed from Open to Closed

This issue was solved with changeset r34450.
Masahiro, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


merge revision(s) r34399:

* vm_eval.c (vm_call0): should pass block to enumerators.  patched
  by Kazuki Tsujimoto.  [ruby-dev:44961][Bug #5731]

* vm_eval.c (method_missing), vm_insnhelper.c (vm_call_method):
  ditto.  patched by satoshi shiba.
Actions #7

Updated by kosaki (Motohiro KOSAKI) about 12 years ago

  • Project changed from Backport193 to Backport192
  • Status changed from Closed to Open

たぶん 1.9.2 にもいるんじゃないかと推測

Actions #8

Updated by naruse (Yui NARUSE) almost 8 years ago

  • Status changed from Open to Rejected
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0