mirror of
https://github.com/ruby/ruby.git
synced 2025-09-24 04:54:01 +02:00
Show the previous definition location,
when reopened class/module redefinition mismatched the previous definition. [Feature #11460]
This commit is contained in:
parent
d3e0bc07e2
commit
761346a960
3 changed files with 36 additions and 12 deletions
|
@ -591,15 +591,17 @@ class TestClass < Test::Unit::TestCase
|
||||||
|
|
||||||
def test_redefinition_mismatch
|
def test_redefinition_mismatch
|
||||||
m = Module.new
|
m = Module.new
|
||||||
m.module_eval "A = 1"
|
m.module_eval "A = 1", __FILE__, line = __LINE__
|
||||||
assert_raise_with_message(TypeError, /is not a class/) {
|
e = assert_raise_with_message(TypeError, /is not a class/) {
|
||||||
m.module_eval "class A; end"
|
m.module_eval "class A; end"
|
||||||
}
|
}
|
||||||
|
assert_include(e.message, "#{__FILE__}:#{line}: previous definition")
|
||||||
n = "M\u{1f5ff}"
|
n = "M\u{1f5ff}"
|
||||||
m.module_eval "#{n} = 42"
|
m.module_eval "#{n} = 42", __FILE__, line = __LINE__
|
||||||
assert_raise_with_message(TypeError, "#{n} is not a class") {
|
e = assert_raise_with_message(TypeError, /#{n} is not a class/) {
|
||||||
m.module_eval "class #{n}; end"
|
m.module_eval "class #{n}; end"
|
||||||
}
|
}
|
||||||
|
assert_include(e.message, "#{__FILE__}:#{line}: previous definition")
|
||||||
|
|
||||||
assert_separately([], "#{<<~"begin;"}\n#{<<~"end;"}")
|
assert_separately([], "#{<<~"begin;"}\n#{<<~"end;"}")
|
||||||
begin;
|
begin;
|
||||||
|
|
|
@ -2383,15 +2383,17 @@ class TestModule < Test::Unit::TestCase
|
||||||
|
|
||||||
def test_redefinition_mismatch
|
def test_redefinition_mismatch
|
||||||
m = Module.new
|
m = Module.new
|
||||||
m.module_eval "A = 1"
|
m.module_eval "A = 1", __FILE__, line = __LINE__
|
||||||
assert_raise_with_message(TypeError, /is not a module/) {
|
e = assert_raise_with_message(TypeError, /is not a module/) {
|
||||||
m.module_eval "module A; end"
|
m.module_eval "module A; end"
|
||||||
}
|
}
|
||||||
|
assert_include(e.message, "#{__FILE__}:#{line}: previous definition")
|
||||||
n = "M\u{1f5ff}"
|
n = "M\u{1f5ff}"
|
||||||
m.module_eval "#{n} = 42"
|
m.module_eval "#{n} = 42", __FILE__, line = __LINE__
|
||||||
assert_raise_with_message(TypeError, "#{n} is not a module") {
|
e = assert_raise_with_message(TypeError, /#{n} is not a module/) {
|
||||||
m.module_eval "module #{n}; end"
|
m.module_eval "module #{n}; end"
|
||||||
}
|
}
|
||||||
|
assert_include(e.message, "#{__FILE__}:#{line}: previous definition")
|
||||||
|
|
||||||
assert_separately([], <<-"end;")
|
assert_separately([], <<-"end;")
|
||||||
Etc = (class C\u{1f5ff}; self; end).new
|
Etc = (class C\u{1f5ff}; self; end).new
|
||||||
|
|
|
@ -3389,7 +3389,7 @@ static VALUE
|
||||||
vm_check_if_class(ID id, rb_num_t flags, VALUE super, VALUE klass)
|
vm_check_if_class(ID id, rb_num_t flags, VALUE super, VALUE klass)
|
||||||
{
|
{
|
||||||
if (!RB_TYPE_P(klass, T_CLASS)) {
|
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)) {
|
else if (VM_DEFINECLASS_HAS_SUPERCLASS_P(flags)) {
|
||||||
VALUE tmp = rb_class_real(RCLASS_SUPER(klass));
|
VALUE tmp = rb_class_real(RCLASS_SUPER(klass));
|
||||||
|
@ -3412,7 +3412,7 @@ static VALUE
|
||||||
vm_check_if_module(ID id, VALUE mod)
|
vm_check_if_module(ID id, VALUE mod)
|
||||||
{
|
{
|
||||||
if (!RB_TYPE_P(mod, T_MODULE)) {
|
if (!RB_TYPE_P(mod, T_MODULE)) {
|
||||||
rb_raise(rb_eTypeError, "%"PRIsVALUE" is not a module", rb_id2str(id));
|
return 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return mod;
|
return mod;
|
||||||
|
@ -3442,6 +3442,22 @@ vm_declare_module(ID id, VALUE cbase)
|
||||||
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
|
static VALUE
|
||||||
vm_define_class(ID id, rb_num_t flags, VALUE cbase, VALUE super)
|
vm_define_class(ID id, rb_num_t flags, VALUE cbase, VALUE super)
|
||||||
{
|
{
|
||||||
|
@ -3458,7 +3474,9 @@ vm_define_class(ID id, rb_num_t flags, VALUE cbase, VALUE super)
|
||||||
/* find klass */
|
/* find klass */
|
||||||
rb_autoload_load(cbase, id);
|
rb_autoload_load(cbase, id);
|
||||||
if ((klass = vm_const_get_under(id, flags, cbase)) != 0) {
|
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 {
|
else {
|
||||||
return vm_declare_class(id, flags, cbase, super);
|
return vm_declare_class(id, flags, cbase, super);
|
||||||
|
@ -3472,7 +3490,9 @@ vm_define_module(ID id, rb_num_t flags, VALUE cbase)
|
||||||
|
|
||||||
vm_check_if_namespace(cbase);
|
vm_check_if_namespace(cbase);
|
||||||
if ((mod = vm_const_get_under(id, flags, cbase)) != 0) {
|
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 {
|
else {
|
||||||
return vm_declare_module(id, cbase);
|
return vm_declare_module(id, cbase);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue