diff options
author | shugo <shugo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-11-02 05:48:29 +0000 |
---|---|---|
committer | shugo <shugo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-11-02 05:48:29 +0000 |
commit | bb504213816e4598f1961b99e115f8ba59bef71f (patch) | |
tree | ff451d7ff4f58697fb5aff4779c4d8d9740481ad | |
parent | 499b5a9197f68e14873e641b737aea40a0f8bc5a (diff) | |
download | ruby-bb504213816e4598f1961b99e115f8ba59bef71f.tar.gz |
* string.c (sym_to_proc, sym_call): A Proc created by Symbol#to_proc
should close over the current refinements.
[ruby-dev:46345] [Bug #7261]
* vm_eval.c (rb_call0, rb_search_method_entry,
rb_funcall_passing_block_with_refinements): add a new argument
`refinements' for the above changes.
* test/ruby/test_refinement.rb: related test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37418 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 12 | ||||
-rw-r--r-- | include/ruby/ruby.h | 2 | ||||
-rw-r--r-- | string.c | 44 | ||||
-rw-r--r-- | test/ruby/test_refinement.rb | 22 | ||||
-rw-r--r-- | vm_eval.c | 31 |
5 files changed, 87 insertions, 24 deletions
@@ -1,3 +1,15 @@ +Fri Nov 2 14:47:53 2012 Shugo Maeda <shugo@ruby-lang.org> + + * string.c (sym_to_proc, sym_call): A Proc created by Symbol#to_proc + should close over the current refinements. + [ruby-dev:46345] [Bug #7261] + + * vm_eval.c (rb_call0, rb_search_method_entry, + rb_funcall_passing_block_with_refinements): add a new argument + `refinements' for the above changes. + + * test/ruby/test_refinement.rb: related test. + Fri Nov 2 08:24:28 2012 Nobuyoshi Nakada <nobu@ruby-lang.org> * proc.c (top_define_method): new method, main.define_method. diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h index 3e513cc63d..8074334269 100644 --- a/include/ruby/ruby.h +++ b/include/ruby/ruby.h @@ -1317,6 +1317,8 @@ VALUE rb_funcall(VALUE, ID, int, ...); VALUE rb_funcall2(VALUE, ID, int, const VALUE*); VALUE rb_funcall3(VALUE, ID, int, const VALUE*); VALUE rb_funcall_passing_block(VALUE, ID, int, const VALUE*); +VALUE rb_funcall_passing_block_with_refinements(VALUE, ID, int, + const VALUE*, VALUE); int rb_scan_args(int, const VALUE*, const char*, ...); VALUE rb_call_super(int, const VALUE*); @@ -14,6 +14,8 @@ #include "ruby/ruby.h" #include "ruby/re.h" #include "ruby/encoding.h" +#include "node.h" +#include "eval_intern.h" #include "internal.h" #include <assert.h> @@ -7605,15 +7607,18 @@ sym_to_sym(VALUE sym) } static VALUE -sym_call(VALUE args, VALUE sym, int argc, VALUE *argv) +sym_call(VALUE args, VALUE p, int argc, VALUE *argv) { VALUE obj; + NODE *memo = RNODE(p); if (argc < 1) { rb_raise(rb_eArgError, "no receiver given"); } obj = argv[0]; - return rb_funcall_passing_block(obj, (ID)sym, argc - 1, argv + 1); + return rb_funcall_passing_block_with_refinements(obj, (ID) memo->u1.id, + argc - 1, argv + 1, + memo->u2.value); } /* @@ -7633,25 +7638,32 @@ sym_to_proc(VALUE sym) VALUE proc; long id, index; VALUE *aryp; - - if (!sym_proc_cache) { - sym_proc_cache = rb_ary_tmp_new(SYM_PROC_CACHE_SIZE * 2); - rb_gc_register_mark_object(sym_proc_cache); - rb_ary_store(sym_proc_cache, SYM_PROC_CACHE_SIZE*2 - 1, Qnil); - } + const NODE *cref = rb_vm_cref(); id = SYM2ID(sym); - index = (id % SYM_PROC_CACHE_SIZE) << 1; + if (NIL_P(cref->nd_refinements)) { + if (!sym_proc_cache) { + sym_proc_cache = rb_ary_tmp_new(SYM_PROC_CACHE_SIZE * 2); + rb_gc_register_mark_object(sym_proc_cache); + rb_ary_store(sym_proc_cache, SYM_PROC_CACHE_SIZE*2 - 1, Qnil); + } - aryp = RARRAY_PTR(sym_proc_cache); - if (aryp[index] == sym) { - return aryp[index + 1]; + index = (id % SYM_PROC_CACHE_SIZE) << 1; + aryp = RARRAY_PTR(sym_proc_cache); + if (aryp[index] == sym) { + return aryp[index + 1]; + } + else { + proc = rb_proc_new(sym_call, + (VALUE) NEW_MEMO(id, Qnil, 0)); + aryp[index] = sym; + aryp[index + 1] = proc; + return proc; + } } else { - proc = rb_proc_new(sym_call, (VALUE)id); - aryp[index] = sym; - aryp[index + 1] = proc; - return proc; + return rb_proc_new(sym_call, + (VALUE) NEW_MEMO(id, cref->nd_refinements, 0)); } } diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb index cecb5a0665..4a0e6d1327 100644 --- a/test/ruby/test_refinement.rb +++ b/test/ruby/test_refinement.rb @@ -600,4 +600,26 @@ class TestRefinement < Test::Unit::TestCase assert_equal(:m1, m.module_eval { c.new.m1 }) assert_equal(:m2, m.module_eval { c.new.m2 }) end + + module SymbolToProc + class C + end + + module M + refine C do + def foo + "foo" + end + end + + def self.call_foo + c = C.new + :foo.to_proc.call(c) + end + end + end + + def test_symbol_to_proc + assert_equal("foo", SymbolToProc::M.call_foo) + end end @@ -266,7 +266,8 @@ stack_check(void) } static inline rb_method_entry_t * - rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr); + rb_search_method_entry(VALUE refinements, VALUE recv, ID mid, + VALUE *defined_class_ptr); static inline int rb_method_call_status(rb_thread_t *th, const rb_method_entry_t *me, call_type scope, VALUE self); #define NOEX_OK NOEX_NOSUPER @@ -286,10 +287,11 @@ static inline int rb_method_call_status(rb_thread_t *th, const rb_method_entry_t */ static inline VALUE rb_call0(VALUE recv, ID mid, int argc, const VALUE *argv, - call_type scope, VALUE self) + call_type scope, VALUE self, VALUE refinements) { VALUE defined_class; - rb_method_entry_t *me = rb_search_method_entry(recv, mid, &defined_class); + rb_method_entry_t *me = + rb_search_method_entry(refinements, recv, mid, &defined_class); rb_thread_t *th = GET_THREAD(); int call_status = rb_method_call_status(th, me, scope, self); @@ -353,7 +355,7 @@ check_funcall(VALUE recv, ID mid, int argc, VALUE *argv) } } - me = rb_search_method_entry(recv, mid, &defined_class); + me = rb_search_method_entry(Qnil, recv, mid, &defined_class); call_status = rb_method_call_status(th, me, CALL_FCALL, Qundef); if (call_status != NOEX_OK) { if (rb_method_basic_definition_p(klass, idMethodMissing)) { @@ -418,7 +420,8 @@ rb_type_str(enum ruby_value_type type) } static inline rb_method_entry_t * -rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr) +rb_search_method_entry(VALUE refinements, VALUE recv, ID mid, + VALUE *defined_class_ptr) { VALUE klass = CLASS_OF(recv); @@ -457,7 +460,8 @@ rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr) rb_id2name(mid), type, (void *)recv, flags, klass); } } - return rb_method_entry_get_with_refinements(Qnil, klass, mid, defined_class_ptr); + return rb_method_entry_get_with_refinements(refinements, klass, mid, + defined_class_ptr); } static inline int @@ -521,7 +525,7 @@ rb_method_call_status(rb_thread_t *th, const rb_method_entry_t *me, call_type sc static inline VALUE rb_call(VALUE recv, ID mid, int argc, const VALUE *argv, call_type scope) { - return rb_call0(recv, mid, argc, argv, scope, Qundef); + return rb_call0(recv, mid, argc, argv, scope, Qundef, Qnil); } NORETURN(static void raise_method_missing(rb_thread_t *th, int argc, const VALUE *argv, @@ -769,6 +773,17 @@ rb_funcall_passing_block(VALUE recv, ID mid, int argc, const VALUE *argv) return rb_call(recv, mid, argc, argv, CALL_PUBLIC); } +VALUE +rb_funcall_passing_block_with_refinements(VALUE recv, ID mid, int argc, + const VALUE *argv, + VALUE refinements) +{ + PASS_PASSED_BLOCK_TH(GET_THREAD()); + + return rb_call0(recv, mid, argc, argv, CALL_PUBLIC, Qundef, + refinements); +} + static VALUE send_internal(int argc, const VALUE *argv, VALUE recv, call_type scope) { @@ -793,7 +808,7 @@ send_internal(int argc, const VALUE *argv, VALUE recv, call_type scope) id = rb_to_id(vid); } PASS_PASSED_BLOCK_TH(th); - return rb_call0(recv, id, argc, argv, scope, self); + return rb_call0(recv, id, argc, argv, scope, self, Qnil); } /* |