Project

General

Profile

Backport #5731

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

Added by tommy (Masahiro Tomita) over 7 years ago. Updated about 3 years ago.

Status:
Rejected
Priority:
Normal
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

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

Associated revisions

Revision 72969cd3
Added by nobu (Nobuyoshi Nakada) over 7 years ago

  • 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.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@34399 b2dd03c8-39d4-4d8f-98ff-823fe69b080e

Revision 34399
Added by nobu (Nobuyoshi Nakada) over 7 years ago

  • 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.

Revision 34399
Added by nobu (Nobuyoshi Nakada) over 7 years ago

  • 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.

Revision 34399
Added by nobu (Nobuyoshi Nakada) over 7 years ago

  • 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.

Revision 34399
Added by nobu (Nobuyoshi Nakada) over 7 years ago

  • 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.

Revision 34399
Added by nobu (Nobuyoshi Nakada) over 7 years ago

  • 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.

Revision 34399
Added by nobu (Nobuyoshi Nakada) over 7 years ago

  • 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.

Revision 4b295bb7
Added by kosaki (Motohiro KOSAKI) over 7 years ago

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.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_9_3@34450 b2dd03c8-39d4-4d8f-98ff-823fe69b080e

History

Updated by ktsj (Kazuki Tsujimoto) over 7 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 7 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 kazuki@callcc.net writes:

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

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

Updated by shiba (satoshi shiba) over 7 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; }
#4

Updated by nobu (Nobuyoshi Nakada) over 7 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.
#5

Updated by nobu (Nobuyoshi Nakada) over 7 years ago

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

Updated by kosaki (Motohiro KOSAKI) over 7 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.
#7

Updated by kosaki (Motohiro KOSAKI) over 7 years ago

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

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

#8

Updated by naruse (Yui NARUSE) about 3 years ago

  • Status changed from Open to Rejected

Also available in: Atom PDF