Project

General

Profile

Feature #11460 » 0001-Show-the-previous-definition-location.patch

nobu (Nobuyoshi Nakada), 07/04/2019 08:22 AM

View differences:

test/ruby/test_class.rb
def test_redefinition_mismatch
m = Module.new
m.module_eval "A = 1"
assert_raise_with_message(TypeError, /is not a class/) {
m.module_eval "A = 1", __FILE__, line = __LINE__
e = assert_raise_with_message(TypeError, /is not a class/) {
m.module_eval "class A; end"
}
assert_include(e.message, "#{__FILE__}:#{line}: previous definition")
n = "M\u{1f5ff}"
m.module_eval "#{n} = 42"
assert_raise_with_message(TypeError, "#{n} is not a class") {
m.module_eval "#{n} = 42", __FILE__, line = __LINE__
e = assert_raise_with_message(TypeError, /#{n} is not a class/) {
m.module_eval "class #{n}; end"
}
assert_include(e.message, "#{__FILE__}:#{line}: previous definition")
assert_separately([], "#{<<~"begin;"}\n#{<<~"end;"}")
begin;
test/ruby/test_module.rb
def test_redefinition_mismatch
m = Module.new
m.module_eval "A = 1"
assert_raise_with_message(TypeError, /is not a module/) {
m.module_eval "A = 1", __FILE__, line = __LINE__
e = assert_raise_with_message(TypeError, /is not a module/) {
m.module_eval "module A; end"
}
assert_include(e.message, "#{__FILE__}:#{line}: previous definition")
n = "M\u{1f5ff}"
m.module_eval "#{n} = 42"
assert_raise_with_message(TypeError, "#{n} is not a module") {
m.module_eval "#{n} = 42", __FILE__, line = __LINE__
e = assert_raise_with_message(TypeError, /#{n} is not a module/) {
m.module_eval "module #{n}; end"
}
assert_include(e.message, "#{__FILE__}:#{line}: previous definition")
assert_separately([], <<-"end;")
Etc = (class C\u{1f5ff}; self; end).new
vm_insnhelper.c
vm_check_if_class(ID id, rb_num_t flags, VALUE super, VALUE klass)
{
if (!RB_TYPE_P(klass, T_CLASS)) {
rb_raise(rb_eTypeError, "%"PRIsVALUE" is not a class", rb_id2str(id));
return 0;
}
else if (VM_DEFINECLASS_HAS_SUPERCLASS_P(flags)) {
VALUE tmp = rb_class_real(RCLASS_SUPER(klass));
......
vm_check_if_module(ID id, VALUE mod)
{
if (!RB_TYPE_P(mod, T_MODULE)) {
rb_raise(rb_eTypeError, "%"PRIsVALUE" is not a module", rb_id2str(id));
return 0;
}
else {
return mod;
......
return mod;
}
NORETURN(static void unmatched_redefinition(const char *type, VALUE cbase, ID id, VALUE old));
static void
unmatched_redefinition(const char *type, VALUE cbase, ID id, VALUE old)
{
VALUE name = rb_id2str(id);
VALUE message = rb_sprintf("%"PRIsVALUE" is not a %s",
name, type);
VALUE location = rb_const_source_location_at(cbase, id);
if (!NIL_P(location)) {
rb_str_catf(message, "\n%"PRIsVALUE":%"PRIsVALUE":"
" previous definition of %"PRIsVALUE" was here",
rb_ary_entry(location, 0), rb_ary_entry(location, 1), name);
}
rb_exc_raise(rb_exc_new_str(rb_eTypeError, message));
}
static VALUE
vm_define_class(ID id, rb_num_t flags, VALUE cbase, VALUE super)
{
......
/* find klass */
rb_autoload_load(cbase, id);
if ((klass = vm_const_get_under(id, flags, cbase)) != 0) {
return vm_check_if_class(id, flags, super, klass);
if (!vm_check_if_class(id, flags, super, klass))
unmatched_redefinition("class", cbase, id, klass);
return klass;
}
else {
return vm_declare_class(id, flags, cbase, super);
......
vm_check_if_namespace(cbase);
if ((mod = vm_const_get_under(id, flags, cbase)) != 0) {
return vm_check_if_module(id, mod);
if (!vm_check_if_module(id, mod))
unmatched_redefinition("module", cbase, id, mod);
return mod;
}
else {
return vm_declare_module(id, cbase);
(2-2/2)