Feature #15751 » Add-FrozenError-receiver.patch
| error.c | ||
|---|---|---|
|     return Qfalse; | ||
| } | ||
| /* | ||
|  * call-seq: | ||
|  *   FrozenError.new(msg=nil, receiver=nil)  -> name_error | ||
|  * | ||
|  * Construct a new FrozenError exception. If given the <i>receiver</i> | ||
|  * parameter may subsequently be examined using the FrozenError#receiver | ||
|  * method. | ||
|  * | ||
|  *    a = [].freeze | ||
|  *    raise FrozenError.new("can't modify frozen array", a) | ||
|  */ | ||
| static VALUE | ||
| frozen_err_initialize(int argc, VALUE *argv, VALUE self) | ||
| { | ||
|     VALUE msg, recv; | ||
|     argc = rb_scan_args(argc, argv, "02", &msg, &recv); | ||
|     if (argc > 1) { | ||
| 	argc--; | ||
| 	rb_ivar_set(self, id_recv, recv); | ||
|     } | ||
|     rb_call_super(argc, argv); | ||
|     return self; | ||
| } | ||
| void | ||
| rb_name_error(ID id, const char *fmt, ...) | ||
| { | ||
| ... | ... | |
|     rb_eRuntimeError = rb_define_class("RuntimeError", rb_eStandardError); | ||
|     rb_eFrozenError = rb_define_class("FrozenError", rb_eRuntimeError); | ||
|     rb_define_method(rb_eFrozenError, "initialize", frozen_err_initialize, -1); | ||
|     rb_define_method(rb_eFrozenError, "receiver", name_err_receiver, 0); | ||
|     rb_eSecurityError = rb_define_class("SecurityError", rb_eException); | ||
|     rb_eNoMemError = rb_define_class("NoMemoryError", rb_eException); | ||
|     rb_eEncodingError = rb_define_class("EncodingError", rb_eStandardError); | ||
| ... | ... | |
|     rb_raise(rb_eFrozenError, "can't modify frozen %s", what); | ||
| } | ||
| void | ||
| rb_raise_frozen_error(VALUE frozen_obj, const char *fmt, ...) | ||
| { | ||
|     va_list args; | ||
|     VALUE exc; | ||
|     va_start(args, fmt); | ||
|     exc = rb_vsprintf(fmt, args); | ||
|     va_end(args); | ||
|     exc = rb_exc_new3(rb_eFrozenError, exc); | ||
|     rb_ivar_set(exc, id_recv, frozen_obj); | ||
|     rb_exc_raise(exc); | ||
| } | ||
| void | ||
| rb_error_frozen_object(VALUE frozen_obj) | ||
| { | ||
| ... | ... | |
| 	VALUE path = rb_ary_entry(debug_info, 0); | ||
| 	VALUE line = rb_ary_entry(debug_info, 1); | ||
| 	rb_raise(rb_eFrozenError, "can't modify frozen %"PRIsVALUE", created at %"PRIsVALUE":%"PRIsVALUE, | ||
| 		 CLASS_OF(frozen_obj), path, line); | ||
| 	rb_raise_frozen_error(frozen_obj, | ||
| 	    "can't modify frozen %"PRIsVALUE", created at %"PRIsVALUE":%"PRIsVALUE, | ||
| 	    CLASS_OF(frozen_obj), path, line); | ||
|     } | ||
|     else { | ||
| 	rb_raise(rb_eFrozenError, "can't modify frozen %"PRIsVALUE, | ||
| 		 CLASS_OF(frozen_obj)); | ||
| 	rb_raise_frozen_error(frozen_obj, "can't modify frozen %"PRIsVALUE, | ||
| 	    CLASS_OF(frozen_obj)); | ||
|     } | ||
| } | ||
| eval.c | ||
|---|---|---|
| 		goto noclass; | ||
| 	    } | ||
| 	} | ||
| 	rb_error_frozen(desc); | ||
| 	rb_raise_frozen_error(klass, "can't modify frozen %s", desc); | ||
|     } | ||
| } | ||
| include/ruby/intern.h | ||
|---|---|---|
| PRINTF_ARGS(NORETURN(void rb_loaderror_with_path(VALUE path, const char*, ...)), 2, 3); | ||
| PRINTF_ARGS(NORETURN(void rb_name_error(ID, const char*, ...)), 2, 3); | ||
| PRINTF_ARGS(NORETURN(void rb_name_error_str(VALUE, const char*, ...)), 2, 3); | ||
| PRINTF_ARGS(NORETURN(void rb_raise_frozen_error(VALUE, const char*, ...)), 2, 3); | ||
| NORETURN(void rb_invalid_str(const char*, const char*)); | ||
| NORETURN(void rb_error_frozen(const char*)); | ||
| NORETURN(void rb_error_frozen_object(VALUE)); | ||
| test/ruby/test_exception.rb | ||
|---|---|---|
|       alias inspect pretty_inspect | ||
|     end | ||
|   def test_frozen_error_receiver | ||
|     obj = Object.new.freeze | ||
|     (obj.foo = 1) rescue (e = $!) | ||
|     assert_equal(obj, e.receiver) | ||
|     obj.singleton_class.const_set(:A, 2) rescue (e = $!) | ||
|     assert_equal(obj.singleton_class, e.receiver) | ||
|   end | ||
|   def test_frozen_error_initialize | ||
|     obj = Object.new | ||
|     exc = FrozenError.new("bar", obj) | ||
|     assert_equal("bar", exc.message) | ||
|     assert_equal(obj, exc.receiver) | ||
|     exc = FrozenError.new("bar") | ||
|     assert_equal("bar", exc.message) | ||
|     assert_raise_with_message(ArgumentError, "no receiver is available") { | ||
|       exc.receiver | ||
|     } | ||
|     exc = FrozenError.new | ||
|     assert_equal("FrozenError", exc.message) | ||
|     assert_raise_with_message(ArgumentError, "no receiver is available") { | ||
|       exc.receiver | ||
|     } | ||
|   end | ||
|   def test_name_error_new_default | ||
|     error = NameError.new | ||
|     assert_equal("NameError", error.message) | ||
| thread.c | ||
|---|---|---|
| rb_thread_local_aset(VALUE thread, ID id, VALUE val) | ||
| { | ||
|     if (OBJ_FROZEN(thread)) { | ||
| 	rb_error_frozen("thread locals"); | ||
| 	rb_raise_frozen_error(thread, "can't modify frozen thread locals"); | ||
|     } | ||
|     return threadptr_local_aset(rb_thread_ptr(thread), id, val); | ||
| ... | ... | |
|     VALUE locals; | ||
|     if (OBJ_FROZEN(thread)) { | ||
| 	rb_error_frozen("thread locals"); | ||
| 	rb_raise_frozen_error(thread, "can't modify frozen thread locals"); | ||
|     } | ||
|     locals = rb_ivar_get(thread, id_locals); | ||