Project

General

Profile

Feature #15751 ยป Add-FrozenError-receiver-v3.patch

jeremyevans0 (Jeremy Evans), 04/07/2019 03:36 AM

View differences:

error.c
1395 1395
    return Qfalse;
1396 1396
}
1397 1397

  
1398
/*
1399
 * call-seq:
1400
 *   FrozenError.new(msg=nil, receiver=nil)  -> name_error
1401
 *
1402
 * Construct a new FrozenError exception. If given the <i>receiver</i>
1403
 * parameter may subsequently be examined using the FrozenError#receiver
1404
 * method.
1405
 *
1406
 *    a = [].freeze
1407
 *    raise FrozenError.new("can't modify frozen array", a)
1408
 */
1409

  
1410
static VALUE
1411
frozen_err_initialize(int argc, VALUE *argv, VALUE self)
1412
{
1413
    VALUE mesg, recv;
1414

  
1415
    argc = rb_scan_args(argc, argv, "02", &mesg, &recv);
1416
    if (argc > 1) {
1417
	argc--;
1418
	rb_ivar_set(self, id_recv, recv);
1419
    }
1420
    rb_call_super(argc, argv);
1421
    return self;
1422
}
1423

  
1398 1424
void
1399 1425
rb_name_error(ID id, const char *fmt, ...)
1400 1426
{
......
2482 2508

  
2483 2509
    rb_eRuntimeError = rb_define_class("RuntimeError", rb_eStandardError);
2484 2510
    rb_eFrozenError = rb_define_class("FrozenError", rb_eRuntimeError);
2511
    rb_define_method(rb_eFrozenError, "initialize", frozen_err_initialize, -1);
2512
    rb_define_method(rb_eFrozenError, "receiver", name_err_receiver, 0);
2485 2513
    rb_eSecurityError = rb_define_class("SecurityError", rb_eException);
2486 2514
    rb_eNoMemError = rb_define_class("NoMemoryError", rb_eException);
2487 2515
    rb_eEncodingError = rb_define_class("EncodingError", rb_eStandardError);
......
2843 2871
    rb_raise(rb_eFrozenError, "can't modify frozen %s", what);
2844 2872
}
2845 2873

  
2874
void
2875
rb_frozen_error_raise(VALUE frozen_obj, const char *fmt, ...)
2876
{
2877
    va_list args;
2878
    VALUE exc, mesg;
2879

  
2880
    va_start(args, fmt);
2881
    mesg = rb_vsprintf(fmt, args);
2882
    va_end(args);
2883
    exc = rb_exc_new3(rb_eFrozenError, mesg);
2884
    rb_ivar_set(exc, id_recv, frozen_obj);
2885
    rb_exc_raise(exc);
2886
}
2887

  
2846 2888
void
2847 2889
rb_error_frozen_object(VALUE frozen_obj)
2848 2890
{
......
2853 2895
	VALUE path = rb_ary_entry(debug_info, 0);
2854 2896
	VALUE line = rb_ary_entry(debug_info, 1);
2855 2897

  
2856
	rb_raise(rb_eFrozenError, "can't modify frozen %"PRIsVALUE", created at %"PRIsVALUE":%"PRIsVALUE,
2857
		 CLASS_OF(frozen_obj), path, line);
2898
	rb_frozen_error_raise(frozen_obj,
2899
	    "can't modify frozen %"PRIsVALUE", created at %"PRIsVALUE":%"PRIsVALUE,
2900
	    CLASS_OF(frozen_obj), path, line);
2858 2901
    }
2859 2902
    else {
2860
	rb_raise(rb_eFrozenError, "can't modify frozen %"PRIsVALUE,
2861
		 CLASS_OF(frozen_obj));
2903
	rb_frozen_error_raise(frozen_obj, "can't modify frozen %"PRIsVALUE,
2904
	    CLASS_OF(frozen_obj));
2862 2905
    }
2863 2906
}
2864 2907

  
eval.c
454 454
		goto noclass;
455 455
	    }
456 456
	}
457
	rb_error_frozen(desc);
457
	rb_frozen_error_raise(klass, "can't modify frozen %s", desc);
458 458
    }
459 459
}
460 460

  
include/ruby/intern.h
278 278
PRINTF_ARGS(NORETURN(void rb_loaderror_with_path(VALUE path, const char*, ...)), 2, 3);
279 279
PRINTF_ARGS(NORETURN(void rb_name_error(ID, const char*, ...)), 2, 3);
280 280
PRINTF_ARGS(NORETURN(void rb_name_error_str(VALUE, const char*, ...)), 2, 3);
281
PRINTF_ARGS(NORETURN(void rb_frozen_error_raise(VALUE, const char*, ...)), 2, 3);
281 282
NORETURN(void rb_invalid_str(const char*, const char*));
282 283
NORETURN(void rb_error_frozen(const char*));
283 284
NORETURN(void rb_error_frozen_object(VALUE));
test/ruby/test_exception.rb
853 853
      alias inspect pretty_inspect
854 854
    end
855 855

  
856
  def test_frozen_error_receiver
857
    obj = Object.new.freeze
858
    (obj.foo = 1) rescue (e = $!)
859
    assert_same(obj, e.receiver)
860
    obj.singleton_class.const_set(:A, 2) rescue (e = $!)
861
    assert_same(obj.singleton_class, e.receiver)
862
  end
863

  
864
  def test_frozen_error_initialize
865
    obj = Object.new
866
    exc = FrozenError.new("bar", obj)
867
    assert_equal("bar", exc.message)
868
    assert_same(obj, exc.receiver)
869

  
870
    exc = FrozenError.new("bar")
871
    assert_equal("bar", exc.message)
872
    assert_raise_with_message(ArgumentError, "no receiver is available") {
873
      exc.receiver
874
    }
875

  
876
    exc = FrozenError.new
877
    assert_equal("FrozenError", exc.message)
878
    assert_raise_with_message(ArgumentError, "no receiver is available") {
879
      exc.receiver
880
    }
881
  end
882

  
856 883
  def test_name_error_new_default
857 884
    error = NameError.new
858 885
    assert_equal("NameError", error.message)
thread.c
3325 3325
rb_thread_local_aset(VALUE thread, ID id, VALUE val)
3326 3326
{
3327 3327
    if (OBJ_FROZEN(thread)) {
3328
	rb_error_frozen("thread locals");
3328
	rb_frozen_error_raise(thread, "can't modify frozen thread locals");
3329 3329
    }
3330 3330

  
3331 3331
    return threadptr_local_aset(rb_thread_ptr(thread), id, val);
......
3402 3402
    VALUE locals;
3403 3403

  
3404 3404
    if (OBJ_FROZEN(thread)) {
3405
	rb_error_frozen("thread locals");
3405
	rb_frozen_error_raise(thread, "can't modify frozen thread locals");
3406 3406
    }
3407 3407

  
3408 3408
    locals = rb_ivar_get(thread, id_locals);
3409
-