[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]