ruby-changes:41887
From: nobu <ko1@a...>
Date: Sun, 28 Feb 2016 13:40:54 +0900 (JST)
Subject: [ruby-changes:41887] nobu:r53961 (trunk): NoMethodError#private_call?
nobu 2016-02-28 13:41:38 +0900 (Sun, 28 Feb 2016) New Revision: 53961 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=53961 Log: NoMethodError#private_call? * error.c (nometh_err_initialize): add private_call? parameter. * error.c (nometh_err_private_call_p): add private_call? method, to tell if the exception raised in private form FCALL or VCALL. [Feature #12043] * vm_eval.c (make_no_method_exception): append private_call? argument. * vm_insnhelper.c (ci_missing_reason): copy FCALL flag. Modified files: trunk/ChangeLog trunk/error.c trunk/test/ruby/test_exception.rb trunk/vm_core.h trunk/vm_eval.c trunk/vm_insnhelper.c trunk/vm_insnhelper.h Index: vm_insnhelper.c =================================================================== --- vm_insnhelper.c (revision 53960) +++ vm_insnhelper.c (revision 53961) @@ -1782,6 +1782,7 @@ ci_missing_reason(const struct rb_call_i https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1782 { enum method_missing_reason stat = MISSING_NOENTRY; if (ci->flag & VM_CALL_VCALL) stat |= MISSING_VCALL; + if (ci->flag & VM_CALL_FCALL) stat |= MISSING_FCALL; if (ci->flag & VM_CALL_SUPER) stat |= MISSING_SUPER; return stat; } @@ -1823,7 +1824,8 @@ vm_call_opt_send(rb_thread_t *th, rb_con https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1824 if (!(ci->mid = rb_check_id(&sym))) { if (rb_method_basic_definition_p(CLASS_OF(calling->recv), idMethodMissing)) { VALUE exc = make_no_method_exception(rb_eNoMethodError, 0, calling->recv, - rb_long2int(calling->argc), &TOPN(i)); + rb_long2int(calling->argc), &TOPN(i), + ci->flag & (VM_CALL_FCALL|VM_CALL_VCALL)); rb_exc_raise(exc); } TOPN(i) = rb_str_intern(sym); Index: vm_insnhelper.h =================================================================== --- vm_insnhelper.h (revision 53960) +++ vm_insnhelper.h (revision 53961) @@ -185,8 +185,8 @@ enum vm_regan_acttype { https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.h#L185 #define GET_GLOBAL_CONSTANT_STATE() (ruby_vm_global_constant_state) #define INC_GLOBAL_CONSTANT_STATE() (++ruby_vm_global_constant_state) -static VALUE make_no_method_exception(VALUE exc, VALUE format, - VALUE obj, int argc, const VALUE *argv); +static VALUE make_no_method_exception(VALUE exc, VALUE format, VALUE obj, + int argc, const VALUE *argv, int priv); static inline struct vm_throw_data * THROW_DATA_NEW(VALUE val, rb_control_frame_t *cf, VALUE st) Index: test/ruby/test_exception.rb =================================================================== --- test/ruby/test_exception.rb (revision 53960) +++ test/ruby/test_exception.rb (revision 53961) @@ -762,6 +762,7 @@ end.join https://github.com/ruby/ruby/blob/trunk/test/ruby/test_exception.rb#L762 assert_equal(:foo, e.name) assert_equal([1, 2], e.args) assert_same(obj, e.receiver) + assert_not_predicate(e, :private_call?) e = assert_raise(NoMethodError) { obj.instance_eval {foo(1, 2)} @@ -769,6 +770,7 @@ end.join https://github.com/ruby/ruby/blob/trunk/test/ruby/test_exception.rb#L770 assert_equal(:foo, e.name) assert_equal([1, 2], e.args) assert_same(obj, e.receiver) + assert_predicate(e, :private_call?) end def test_name_error_info_local_variables @@ -787,6 +789,29 @@ end.join https://github.com/ruby/ruby/blob/trunk/test/ruby/test_exception.rb#L789 assert_equal(%i[a b c d e f g], e.local_variables.sort) end + def test_name_error_info_method_missing + obj = PrettyObject.new + def obj.method_missing(*) + super + end + + e = assert_raise(NoMethodError) { + obj.foo(1, 2) + } + assert_equal(:foo, e.name) + assert_equal([1, 2], e.args) + assert_same(obj, e.receiver) + assert_not_predicate(e, :private_call?) + + e = assert_raise(NoMethodError) { + obj.instance_eval {foo(1, 2)} + } + assert_equal(:foo, e.name) + assert_equal([1, 2], e.args) + assert_same(obj, e.receiver) + assert_predicate(e, :private_call?) + end + def test_name_error_info_parent_iseq_mark assert_separately(['-', File.join(__dir__, 'bug-11928.rb')], <<-'end;') -> {require ARGV[0]}.call Index: ChangeLog =================================================================== --- ChangeLog (revision 53960) +++ ChangeLog (revision 53961) @@ -1,3 +1,16 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Sun Feb 28 13:40:46 2016 Nobuyoshi Nakada <nobu@r...> + + * error.c (nometh_err_initialize): add private_call? parameter. + + * error.c (nometh_err_private_call_p): add private_call? method, + to tell if the exception raised in private form FCALL or VCALL. + [Feature #12043] + + * vm_eval.c (make_no_method_exception): append private_call? + argument. + + * vm_insnhelper.c (ci_missing_reason): copy FCALL flag. + Sun Feb 28 10:19:47 2016 Ryan T. Hosford <tad.hosford@g...> * array.c (rb_ary_and): clarify that set intersection returns the Index: vm_core.h =================================================================== --- vm_core.h (revision 53960) +++ vm_core.h (revision 53961) @@ -200,10 +200,11 @@ enum method_missing_reason { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L200 MISSING_NOENTRY = 0x00, MISSING_PRIVATE = 0x01, MISSING_PROTECTED = 0x02, - MISSING_VCALL = 0x04, - MISSING_SUPER = 0x08, - MISSING_MISSING = 0x10, - MISSING_NONE = 0x20 + MISSING_FCALL = 0x04, + MISSING_VCALL = 0x08, + MISSING_SUPER = 0x10, + MISSING_MISSING = 0x20, + MISSING_NONE = 0x40 }; struct rb_call_info { Index: vm_eval.c =================================================================== --- vm_eval.c (revision 53960) +++ vm_eval.c (revision 53961) @@ -682,13 +682,15 @@ rb_method_missing(int argc, const VALUE https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L682 } static VALUE -make_no_method_exception(VALUE exc, VALUE format, VALUE obj, int argc, const VALUE *argv) +make_no_method_exception(VALUE exc, VALUE format, VALUE obj, + int argc, const VALUE *argv, int priv) { int n = 0; enum { arg_mesg, arg_name, arg_args, + arg_priv, args_size }; VALUE args[args_size]; @@ -700,6 +702,7 @@ make_no_method_exception(VALUE exc, VALU https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L702 args[n++] = argv[0]; if (exc == rb_eNoMethodError) { args[n++] = rb_ary_new4(argc - 1, argv + 1); + args[n++] = priv ? Qtrue : Qfalse; } return rb_class_new_instance(n, args, exc); } @@ -737,7 +740,8 @@ raise_method_missing(rb_thread_t *th, in https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L740 } { - exc = make_no_method_exception(exc, format, obj, argc, argv); + exc = make_no_method_exception(exc, format, obj, argc, argv, + last_call_status & (MISSING_FCALL|MISSING_VCALL)); if (!(last_call_status & MISSING_MISSING)) { rb_vm_pop_cfunc_frame(); } @@ -929,7 +933,8 @@ send_internal(int argc, const VALUE *arg https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L933 if (!id) { if (rb_method_basic_definition_p(CLASS_OF(recv), idMethodMissing)) { VALUE exc = make_no_method_exception(rb_eNoMethodError, 0, - recv, argc, argv); + recv, argc, argv, + scope != CALL_PUBLIC); rb_exc_raise(exc); } if (!SYMBOL_P(*argv)) { Index: error.c =================================================================== --- error.c (revision 53960) +++ error.c (revision 53961) @@ -697,6 +697,7 @@ static VALUE rb_eNOERROR; https://github.com/ruby/ruby/blob/trunk/error.c#L697 static ID id_new, id_cause, id_message, id_backtrace; static ID id_name, id_args, id_Errno, id_errno, id_i_path; static ID id_receiver, id_iseq, id_local_variables; +static ID id_private_call_p; extern ID ruby_static_id_status; #define id_bt idBt #define id_bt_locations idBt_locations @@ -1203,9 +1204,11 @@ name_err_local_variables(VALUE self) https://github.com/ruby/ruby/blob/trunk/error.c#L1204 static VALUE nometh_err_initialize(int argc, VALUE *argv, VALUE self) { + VALUE priv = (argc > 3) && (--argc, RTEST(argv[argc])) ? Qtrue : Qfalse; VALUE args = (argc > 2) ? argv[--argc] : Qnil; name_err_initialize(argc, argv, self); rb_ivar_set(self, id_args, args); + rb_ivar_set(self, id_private_call_p, RTEST(priv) ? Qtrue : Qfalse); return self; } @@ -1392,6 +1395,12 @@ nometh_err_args(VALUE self) https://github.com/ruby/ruby/blob/trunk/error.c#L1395 return rb_attr_get(self, id_args); } +static VALUE +nometh_err_private_call_p(VALUE self) +{ + return rb_attr_get(self, id_private_call_p); +} + void rb_invalid_str(const char *str, const char *type) { @@ -2019,6 +2028,7 @@ Init_Exception(void) https://github.com/ruby/ruby/blob/trunk/error.c#L2028 rb_eNoMethodError = rb_define_class("NoMethodError", rb_eNameError); rb_define_method(rb_eNoMethodError, "initialize", nometh_err_initialize, -1); rb_define_method(rb_eNoMethodError, "args", nometh_err_args, 0); + rb_define_method(rb_eNoMethodError, "private_call?", nometh_err_private_call_p, 0); rb_eRuntimeError = rb_define_class("RuntimeError", rb_eStandardError); rb_eSecurityError = rb_define_class("SecurityError", rb_eException); @@ -2043,6 +2053,7 @@ Init_Exception(void) https://github.com/ruby/ruby/blob/trunk/error.c#L2053 id_name = rb_intern_const("name"); id_args = rb_intern_const("args"); id_receiver = rb_intern_const("receiver"); + id_private_call_p = rb_intern_const("private_call?"); id_local_variables = rb_intern_const("local_variables"); id_Errno = rb_intern_const("Errno"); id_errno = rb_intern_const("errno"); -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/