summaryrefslogtreecommitdiff
path: root/error.c
diff options
context:
space:
mode:
authorYusuke Endoh <mame@ruby-lang.org>2022-12-16 07:31:27 +0900
committerYusuke Endoh <mame@ruby-lang.org>2023-02-20 10:33:06 +0900
commite7b8d32e166815f2e7edebf32aa178915d191b8c (patch)
tree94f8b15c9d5644886c545404756f68dcf37d4eff /error.c
parent5c0298bf181921a8aa63cd250d67b294cfe90322 (diff)
downloadruby-e7b8d32e166815f2e7edebf32aa178915d191b8c.tar.gz
Stop using receiver#inspect for "undefined method" errors
``` 42.time #=> undefined method `time' for object Integer (NoMethodError) class Foo privatee #=> undefined local variable or method 'privatee' for class Foo (NoMethodError) end s = "" def s.foo = nil s.bar #=> undefined method `bar' for extended object String (NoMethodError) ``` [Feature #18285]
Diffstat (limited to 'error.c')
-rw-r--r--error.c71
1 files changed, 52 insertions, 19 deletions
diff --git a/error.c b/error.c
index 8aa081c198..affee7d828 100644
--- a/error.c
+++ b/error.c
@@ -2066,43 +2066,76 @@ name_err_mesg_to_str(VALUE obj)
if (NIL_P(mesg)) return Qnil;
else {
struct RString s_str, d_str;
- VALUE c, s, d = 0, args[4];
- int state = 0, singleton = 0;
+ VALUE c, s, d = 0, args[4], c2;
+ int state = 0;
rb_encoding *usascii = rb_usascii_encoding();
#define FAKE_CSTR(v, str) rb_setup_fake_str((v), (str), rb_strlen_lit(str), usascii)
+ c = s = FAKE_CSTR(&s_str, "");
obj = ptr[NAME_ERR_MESG__RECV];
switch (obj) {
case Qnil:
- d = FAKE_CSTR(&d_str, "nil");
+ c = d = FAKE_CSTR(&d_str, "nil");
break;
case Qtrue:
- d = FAKE_CSTR(&d_str, "true");
+ c = d = FAKE_CSTR(&d_str, "true");
break;
case Qfalse:
- d = FAKE_CSTR(&d_str, "false");
+ c = d = FAKE_CSTR(&d_str, "false");
break;
default:
- d = rb_protect(name_err_mesg_receiver_name, obj, &state);
- if (state || NIL_OR_UNDEF_P(d))
- d = rb_protect(rb_inspect, obj, &state);
+ if (strstr(RSTRING_PTR(mesg), "%2$s")) {
+ d = rb_protect(name_err_mesg_receiver_name, obj, &state);
+ if (state || NIL_OR_UNDEF_P(d))
+ d = rb_protect(rb_inspect, obj, &state);
+ if (state) {
+ rb_set_errinfo(Qnil);
+ }
+ d = rb_check_string_type(d);
+ if (NIL_P(d)) {
+ d = rb_any_to_s(obj);
+ }
+ }
+
+ if (!RB_SPECIAL_CONST_P(obj)) {
+ switch (RB_BUILTIN_TYPE(obj)) {
+ case T_MODULE:
+ s = FAKE_CSTR(&s_str, "module ");
+ c = obj;
+ break;
+ case T_CLASS:
+ s = FAKE_CSTR(&s_str, "class ");
+ c = obj;
+ break;
+ default:
+ goto object;
+ }
+ }
+ else {
+ VALUE klass;
+object:
+ klass = CLASS_OF(obj);
+ if (RB_TYPE_P(klass, T_CLASS) && FL_TEST(klass, FL_SINGLETON)) {
+ s = FAKE_CSTR(&s_str, "extended object ");
+ }
+ else {
+ s = FAKE_CSTR(&s_str, "object ");
+ }
+ c = rb_class_real(klass);
+ }
+ c2 = rb_protect(name_err_mesg_receiver_name, c, &state);
+ if (state || NIL_OR_UNDEF_P(c2))
+ c2 = rb_protect(rb_inspect, c, &state);
if (state) {
rb_set_errinfo(Qnil);
}
- d = rb_check_string_type(d);
- if (NIL_P(d)) {
- d = rb_any_to_s(obj);
+ c2 = rb_check_string_type(c2);
+ if (NIL_P(c2)) {
+ c2 = rb_any_to_s(c);
}
- singleton = (RSTRING_LEN(d) > 0 && RSTRING_PTR(d)[0] == '#');
+ c = c2;
break;
}
- if (!singleton) {
- s = FAKE_CSTR(&s_str, ":");
- c = rb_class_name(CLASS_OF(obj));
- }
- else {
- c = s = FAKE_CSTR(&s_str, "");
- }
args[0] = rb_obj_as_string(ptr[NAME_ERR_MESG__NAME]);
args[1] = d;
args[2] = s;