summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean Boussier <jean.boussier@gmail.com>2026-02-05 20:38:00 +0100
committerBenoit Daloze <eregontp@gmail.com>2026-02-07 10:06:36 +0100
commitd066b9e01ccb2260fac8b2580c10e73335c7c7db (patch)
treeece08ae6b0309149e09a640a3b41537a6485ee13
parent96d00640978d78ede1f5b2b63e422cfd1e849891 (diff)
Refactor type error to be more consistent
[Bug #21864] Co-Authored-By: Benoit Daloze <eregontp@gmail.com>
-rw-r--r--complex.c3
-rw-r--r--depend6
-rw-r--r--error.c62
-rw-r--r--internal/error.h3
-rw-r--r--numeric.c16
-rw-r--r--object.c67
-rw-r--r--rational.c3
-rw-r--r--spec/mspec/lib/mspec/matchers/raise_error.rb11
-rw-r--r--spec/ruby/core/array/try_convert_spec.rb2
-rw-r--r--spec/ruby/core/basicobject/instance_eval_spec.rb6
-rw-r--r--spec/ruby/core/data/deconstruct_keys_spec.rb2
-rw-r--r--spec/ruby/core/dir/for_fd_spec.rb2
-rw-r--r--spec/ruby/core/hash/try_convert_spec.rb2
-rw-r--r--spec/ruby/core/integer/try_convert_spec.rb4
-rw-r--r--spec/ruby/core/io/lineno_spec.rb2
-rw-r--r--spec/ruby/core/io/try_convert_spec.rb2
-rw-r--r--spec/ruby/core/kernel/Rational_spec.rb2
-rw-r--r--spec/ruby/core/kernel/shared/sprintf.rb8
-rw-r--r--spec/ruby/core/module/define_method_spec.rb2
-rw-r--r--spec/ruby/core/module/instance_method_spec.rb2
-rw-r--r--spec/ruby/core/module/shared/class_eval.rb4
-rw-r--r--spec/ruby/core/process/detach_spec.rb2
-rw-r--r--spec/ruby/core/queue/initialize_spec.rb2
-rw-r--r--spec/ruby/core/regexp/shared/new.rb2
-rw-r--r--spec/ruby/core/regexp/try_convert_spec.rb2
-rw-r--r--spec/ruby/core/string/try_convert_spec.rb2
-rw-r--r--spec/ruby/core/struct/deconstruct_keys_spec.rb2
-rw-r--r--spec/ruby/language/send_spec.rb2
-rw-r--r--spec/ruby/shared/queue/deque.rb4
-rw-r--r--spec/ruby/shared/sizedqueue/enque.rb4
-rw-r--r--spec/ruby/shared/types/rb_num2dbl_fails.rb6
-rw-r--r--test/error_highlight/test_error_highlight.rb7
-rw-r--r--test/ruby/test_exception.rb6
-rw-r--r--test/ruby/test_integer.rb2
-rw-r--r--time.c7
-rw-r--r--vm_args.c9
36 files changed, 158 insertions, 112 deletions
diff --git a/complex.c b/complex.c
index 1ba786a5bb..c47afc1a61 100644
--- a/complex.c
+++ b/complex.c
@@ -20,6 +20,7 @@
#include "internal/array.h"
#include "internal/class.h"
#include "internal/complex.h"
+#include "internal/error.h"
#include "internal/math.h"
#include "internal/numeric.h"
#include "internal/object.h"
@@ -2411,7 +2412,7 @@ nucomp_convert(VALUE klass, VALUE a1, VALUE a2, int raise)
{
if (NIL_P(a1) || NIL_P(a2)) {
if (!raise) return Qnil;
- rb_raise(rb_eTypeError, "can't convert nil into Complex");
+ rb_cant_convert(Qnil, "Complex");
}
if (RB_TYPE_P(a1, T_STRING)) {
diff --git a/depend b/depend
index 978ac438b9..85ba50fa6e 100644
--- a/depend
+++ b/depend
@@ -1892,6 +1892,7 @@ complex.$(OBJEXT): $(top_srcdir)/internal/box.h
complex.$(OBJEXT): $(top_srcdir)/internal/class.h
complex.$(OBJEXT): $(top_srcdir)/internal/compilers.h
complex.$(OBJEXT): $(top_srcdir)/internal/complex.h
+complex.$(OBJEXT): $(top_srcdir)/internal/error.h
complex.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
complex.$(OBJEXT): $(top_srcdir)/internal/gc.h
complex.$(OBJEXT): $(top_srcdir)/internal/imemo.h
@@ -9963,6 +9964,7 @@ numeric.$(OBJEXT): $(top_srcdir)/internal/class.h
numeric.$(OBJEXT): $(top_srcdir)/internal/compilers.h
numeric.$(OBJEXT): $(top_srcdir)/internal/complex.h
numeric.$(OBJEXT): $(top_srcdir)/internal/enumerator.h
+numeric.$(OBJEXT): $(top_srcdir)/internal/error.h
numeric.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
numeric.$(OBJEXT): $(top_srcdir)/internal/gc.h
numeric.$(OBJEXT): $(top_srcdir)/internal/hash.h
@@ -13221,6 +13223,7 @@ rational.$(OBJEXT): $(top_srcdir)/internal/box.h
rational.$(OBJEXT): $(top_srcdir)/internal/class.h
rational.$(OBJEXT): $(top_srcdir)/internal/compilers.h
rational.$(OBJEXT): $(top_srcdir)/internal/complex.h
+rational.$(OBJEXT): $(top_srcdir)/internal/error.h
rational.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
rational.$(OBJEXT): $(top_srcdir)/internal/gc.h
rational.$(OBJEXT): $(top_srcdir)/internal/imemo.h
@@ -13231,6 +13234,7 @@ rational.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
rational.$(OBJEXT): $(top_srcdir)/internal/serial.h
rational.$(OBJEXT): $(top_srcdir)/internal/set_table.h
rational.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+rational.$(OBJEXT): $(top_srcdir)/internal/string.h
rational.$(OBJEXT): $(top_srcdir)/internal/variable.h
rational.$(OBJEXT): $(top_srcdir)/internal/vm.h
rational.$(OBJEXT): $(top_srcdir)/internal/warnings.h
@@ -13248,6 +13252,7 @@ rational.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
rational.$(OBJEXT): {$(VPATH)}config.h
rational.$(OBJEXT): {$(VPATH)}constant.h
rational.$(OBJEXT): {$(VPATH)}defines.h
+rational.$(OBJEXT): {$(VPATH)}encindex.h
rational.$(OBJEXT): {$(VPATH)}encoding.h
rational.$(OBJEXT): {$(VPATH)}id.h
rational.$(OBJEXT): {$(VPATH)}id_table.h
@@ -17669,6 +17674,7 @@ time.$(OBJEXT): $(top_srcdir)/internal/bits.h
time.$(OBJEXT): $(top_srcdir)/internal/box.h
time.$(OBJEXT): $(top_srcdir)/internal/compar.h
time.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+time.$(OBJEXT): $(top_srcdir)/internal/error.h
time.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
time.$(OBJEXT): $(top_srcdir)/internal/gc.h
time.$(OBJEXT): $(top_srcdir)/internal/hash.h
diff --git a/error.c b/error.c
index d6518feb34..140049fdd2 100644
--- a/error.c
+++ b/error.c
@@ -2758,6 +2758,68 @@ nometh_err_private_call_p(VALUE self)
return rb_attr_get(self, id_private_call_p);
}
+static const char *
+type_err_cname(VALUE val)
+{
+ if (NIL_P(val)) {
+ return "nil";
+ }
+ else if (val == Qtrue) {
+ return "true";
+ }
+ else if (val == Qfalse) {
+ return "false";
+ }
+ return NULL;
+}
+
+NORETURN(static void type_err_raise(VALUE val, const char *tname, const char *msg));
+static void
+type_err_raise(VALUE val, const char *tname, const char *msg)
+{
+ const char *cname = type_err_cname(val);
+ rb_encoding *enc = rb_utf8_encoding();
+ if (cname) {
+ rb_enc_raise(enc, rb_eTypeError, "%s %s into %s", msg, cname, tname);
+ }
+ rb_enc_raise(enc, rb_eTypeError, "%s %"PRIsVALUE" into %s", msg, rb_obj_class(val), tname);
+}
+
+NORETURN(void rb_no_implicit_conversion(VALUE val, const char *tname));
+void
+rb_no_implicit_conversion(VALUE val, const char *tname)
+{
+ type_err_raise(val, tname, "no implicit conversion of");
+}
+
+NORETURN(void rb_cant_convert(VALUE val, const char *tname));
+void
+rb_cant_convert(VALUE val, const char *tname)
+{
+ type_err_raise(val, tname, "can't convert");
+}
+
+NORETURN(void rb_cant_convert_invalid_return(VALUE val, const char *tname, const char *method_name, VALUE ret));
+void
+rb_cant_convert_invalid_return(VALUE val, const char *tname, const char *method_name, VALUE ret)
+{
+ const char *cname = type_err_cname(val);
+ rb_encoding *enc = rb_utf8_encoding();
+ if (cname) {
+ rb_enc_raise(
+ enc, rb_eTypeError, "can't convert %s into %s (%s#%s gives %s)",
+ cname, tname, cname, method_name, type_err_cname(ret));
+ }
+ VALUE klass = rb_obj_class(val);
+ const char *retname = type_err_cname(ret);
+ if (!retname) {
+ retname = rb_obj_classname(ret);
+ }
+ rb_enc_raise(
+ enc, rb_eTypeError, "can't convert %"PRIsVALUE" into %s (%"PRIsVALUE"#%s gives %s)",
+ klass, tname, klass, method_name, retname);
+}
+
void
rb_invalid_str(const char *str, const char *type)
{
diff --git a/internal/error.h b/internal/error.h
index ae9a13fcec..fead2aee95 100644
--- a/internal/error.h
+++ b/internal/error.h
@@ -186,6 +186,9 @@ static inline void Check_Type(VALUE v, enum ruby_value_type t);
static inline bool rb_typeddata_is_instance_of_inline(VALUE obj, const rb_data_type_t *data_type);
#define rb_typeddata_is_instance_of rb_typeddata_is_instance_of_inline
void rb_bug_without_die(const char *fmt, ...);
+NORETURN(void rb_no_implicit_conversion(VALUE val, const char *tname));
+NORETURN(void rb_cant_convert(VALUE val, const char *tname));
+NORETURN(void rb_cant_convert_invalid_return(VALUE val, const char *tname, const char *method_name, VALUE ret));
RUBY_SYMBOL_EXPORT_BEGIN
/* error.c (export) */
diff --git a/numeric.c b/numeric.c
index 3610188294..3c44d39443 100644
--- a/numeric.c
+++ b/numeric.c
@@ -30,6 +30,7 @@
#include "internal/compilers.h"
#include "internal/complex.h"
#include "internal/enumerator.h"
+#include "internal/error.h"
#include "internal/gc.h"
#include "internal/hash.h"
#include "internal/numeric.h"
@@ -3102,7 +3103,7 @@ rb_num2long(VALUE val)
{
again:
if (NIL_P(val)) {
- rb_raise(rb_eTypeError, "no implicit conversion from nil to integer");
+ rb_no_implicit_conversion(val, "Integer");
}
if (FIXNUM_P(val)) return FIX2LONG(val);
@@ -3130,7 +3131,7 @@ rb_num2ulong_internal(VALUE val, int *wrap_p)
{
again:
if (NIL_P(val)) {
- rb_raise(rb_eTypeError, "no implicit conversion of nil into Integer");
+ rb_no_implicit_conversion(val, "Integer");
}
if (FIXNUM_P(val)) {
@@ -3373,7 +3374,7 @@ LONG_LONG
rb_num2ll(VALUE val)
{
if (NIL_P(val)) {
- rb_raise(rb_eTypeError, "no implicit conversion from nil");
+ rb_no_implicit_conversion(val, "Integer");
}
if (FIXNUM_P(val)) return (LONG_LONG)FIX2LONG(val);
@@ -3390,11 +3391,8 @@ rb_num2ll(VALUE val)
else if (RB_BIGNUM_TYPE_P(val)) {
return rb_big2ll(val);
}
- else if (RB_TYPE_P(val, T_STRING)) {
- rb_raise(rb_eTypeError, "no implicit conversion from string");
- }
- else if (RB_TYPE_P(val, T_TRUE) || RB_TYPE_P(val, T_FALSE)) {
- rb_raise(rb_eTypeError, "no implicit conversion from boolean");
+ else if (val == Qfalse || val == Qtrue || RB_TYPE_P(val, T_STRING)) {
+ rb_no_implicit_conversion(val, "Integer");
}
val = rb_to_int(val);
@@ -3405,7 +3403,7 @@ unsigned LONG_LONG
rb_num2ull(VALUE val)
{
if (NIL_P(val)) {
- rb_raise(rb_eTypeError, "no implicit conversion of nil into Integer");
+ rb_no_implicit_conversion(val, "Integer");
}
else if (FIXNUM_P(val)) {
return (LONG_LONG)FIX2LONG(val); /* this is FIX2LONG, intended */
diff --git a/object.c b/object.c
index 24202f069e..4dcd5d615f 100644
--- a/object.c
+++ b/object.c
@@ -3332,19 +3332,12 @@ convert_type_with_id(VALUE val, const char *tname, ID method, int raise, int ind
VALUE r = rb_check_funcall(val, method, 0, 0);
if (UNDEF_P(r)) {
if (raise) {
- const char *msg =
- ((index < 0 ? conv_method_index(rb_id2name(method)) : index)
- < IMPLICIT_CONVERSIONS) ?
- "no implicit conversion of" : "can't convert";
- const char *cname = NIL_P(val) ? "nil" :
- val == Qtrue ? "true" :
- val == Qfalse ? "false" :
- NULL;
- if (cname)
- rb_raise(rb_eTypeError, "%s %s into %s", msg, cname, tname);
- rb_raise(rb_eTypeError, "%s %"PRIsVALUE" into %s", msg,
- rb_obj_class(val),
- tname);
+ if ((index < 0 ? conv_method_index(rb_id2name(method)) : index) < IMPLICIT_CONVERSIONS) {
+ rb_no_implicit_conversion(val, tname);
+ }
+ else {
+ rb_cant_convert(val, tname);
+ }
}
return Qnil;
}
@@ -3360,17 +3353,6 @@ convert_type(VALUE val, const char *tname, const char *method, int raise)
return convert_type_with_id(val, tname, m, raise, i);
}
-/*! \private */
-NORETURN(static void conversion_mismatch(VALUE, const char *, const char *, VALUE));
-static void
-conversion_mismatch(VALUE val, const char *tname, const char *method, VALUE result)
-{
- VALUE cname = rb_obj_class(val);
- rb_raise(rb_eTypeError,
- "can't convert %"PRIsVALUE" to %s (%"PRIsVALUE"#%s gives %"PRIsVALUE")",
- cname, tname, cname, method, rb_obj_class(result));
-}
-
VALUE
rb_convert_type(VALUE val, int type, const char *tname, const char *method)
{
@@ -3379,7 +3361,7 @@ rb_convert_type(VALUE val, int type, const char *tname, const char *method)
if (TYPE(val) == type) return val;
v = convert_type(val, tname, method, TRUE);
if (TYPE(v) != type) {
- conversion_mismatch(val, tname, method, v);
+ rb_cant_convert_invalid_return(val, tname, method, v);
}
return v;
}
@@ -3393,7 +3375,7 @@ rb_convert_type_with_id(VALUE val, int type, const char *tname, ID method)
if (TYPE(val) == type) return val;
v = convert_type_with_id(val, tname, method, TRUE, -1);
if (TYPE(v) != type) {
- conversion_mismatch(val, tname, RSTRING_PTR(rb_id2str(method)), v);
+ rb_cant_convert_invalid_return(val, tname, rb_id2name(method), v);
}
return v;
}
@@ -3408,7 +3390,7 @@ rb_check_convert_type(VALUE val, int type, const char *tname, const char *method
v = convert_type(val, tname, method, FALSE);
if (NIL_P(v)) return Qnil;
if (TYPE(v) != type) {
- conversion_mismatch(val, tname, method, v);
+ rb_cant_convert_invalid_return(val, tname, method, v);
}
return v;
}
@@ -3424,7 +3406,7 @@ rb_check_convert_type_with_id(VALUE val, int type, const char *tname, ID method)
v = convert_type_with_id(val, tname, method, FALSE, -1);
if (NIL_P(v)) return Qnil;
if (TYPE(v) != type) {
- conversion_mismatch(val, tname, RSTRING_PTR(rb_id2str(method)), v);
+ rb_cant_convert_invalid_return(val, tname, rb_id2name(method), v);
}
return v;
}
@@ -3450,7 +3432,7 @@ rb_to_integer_with_id_exception(VALUE val, const char *method, ID mid, int raise
return Qnil;
}
if (!RB_INTEGER_TYPE_P(v)) {
- conversion_mismatch(val, "Integer", method, v);
+ rb_cant_convert_invalid_return(val, "Integer", method, v);
}
GET_EC()->cfp = current_cfp;
return v;
@@ -3527,7 +3509,7 @@ rb_convert_to_integer(VALUE val, int base, int raise_exception)
}
else if (NIL_P(val)) {
if (!raise_exception) return Qnil;
- rb_raise(rb_eTypeError, "can't convert nil into Integer");
+ rb_cant_convert(val, "Integer");
}
tmp = rb_protect(rb_check_to_int, val, NULL);
@@ -3821,18 +3803,6 @@ rat2dbl_without_to_f(VALUE x)
}
/*! \endcond */
-static inline void
-conversion_to_float(VALUE val)
-{
- special_const_to_float(val, "can't convert ", " into Float");
-}
-
-static inline void
-implicit_conversion_to_float(VALUE val)
-{
- special_const_to_float(val, "no implicit conversion to float from ", "");
-}
-
static int
to_float(VALUE *valp, int raise_exception)
{
@@ -3846,7 +3816,7 @@ to_float(VALUE *valp, int raise_exception)
return T_FLOAT;
}
else if (raise_exception) {
- conversion_to_float(val);
+ rb_cant_convert(val, "Float");
}
}
else {
@@ -3926,8 +3896,7 @@ static VALUE
numeric_to_float(VALUE val)
{
if (!rb_obj_is_kind_of(val, rb_cNumeric)) {
- rb_raise(rb_eTypeError, "can't convert %"PRIsVALUE" into Float",
- rb_obj_class(val));
+ rb_cant_convert(val, "Float");
}
return rb_convert_type_with_id(val, T_FLOAT, "Float", id_to_f);
}
@@ -3971,7 +3940,7 @@ rb_num_to_dbl(VALUE val)
return rb_float_flonum_value(val);
}
else {
- conversion_to_float(val);
+ rb_cant_convert(val, "Float");
}
}
else {
@@ -4005,7 +3974,7 @@ rb_num2dbl(VALUE val)
return rb_float_flonum_value(val);
}
else {
- implicit_conversion_to_float(val);
+ rb_no_implicit_conversion(val, "Float");
}
}
else {
@@ -4017,7 +3986,7 @@ rb_num2dbl(VALUE val)
case T_RATIONAL:
return rat2dbl_without_to_f(val);
case T_STRING:
- rb_raise(rb_eTypeError, "no implicit conversion to float from string");
+ rb_no_implicit_conversion(val, "Float");
default:
break;
}
@@ -4111,7 +4080,7 @@ rb_Hash(VALUE val)
if (NIL_P(tmp)) {
if (RB_TYPE_P(val, T_ARRAY) && RARRAY_LEN(val) == 0)
return rb_hash_new();
- rb_raise(rb_eTypeError, "can't convert %s into Hash", rb_obj_classname(val));
+ rb_cant_convert(val, "Hash");
}
return tmp;
}
diff --git a/rational.c b/rational.c
index 51078f81ad..fba93a5c3f 100644
--- a/rational.c
+++ b/rational.c
@@ -27,6 +27,7 @@
#include "internal.h"
#include "internal/array.h"
#include "internal/complex.h"
+#include "internal/error.h"
#include "internal/gc.h"
#include "internal/numeric.h"
#include "internal/object.h"
@@ -2562,7 +2563,7 @@ nurat_convert(VALUE klass, VALUE numv, VALUE denv, int raise)
if (NIL_P(a1) || NIL_P(a2)) {
if (!raise) return Qnil;
- rb_raise(rb_eTypeError, "can't convert nil into Rational");
+ rb_cant_convert(Qnil, "Rational");
}
if (RB_TYPE_P(a1, T_COMPLEX)) {
diff --git a/spec/mspec/lib/mspec/matchers/raise_error.rb b/spec/mspec/lib/mspec/matchers/raise_error.rb
index 54378bb34c..2aa3038ed1 100644
--- a/spec/mspec/lib/mspec/matchers/raise_error.rb
+++ b/spec/mspec/lib/mspec/matchers/raise_error.rb
@@ -90,4 +90,15 @@ module MSpecMatchers
private def raise_error(exception = Exception, message = nil, &block)
RaiseErrorMatcher.new(exception, message, &block)
end
+
+ # CRuby < 4.1 has inconsistent coercion errors:
+ # https://bugs.ruby-lang.org/issues/21864
+ # This matcher ignores the message on CRuby < 4.1
+ # and checks the message for all other cases, including other Rubies
+ private def raise_consistent_error(exception = Exception, message = nil, &block)
+ if RUBY_ENGINE == "ruby" and ruby_version_is ""..."4.1"
+ message = nil
+ end
+ RaiseErrorMatcher.new(exception, message, &block)
+ end
end
diff --git a/spec/ruby/core/array/try_convert_spec.rb b/spec/ruby/core/array/try_convert_spec.rb
index bea8815006..2d5e14375f 100644
--- a/spec/ruby/core/array/try_convert_spec.rb
+++ b/spec/ruby/core/array/try_convert_spec.rb
@@ -39,7 +39,7 @@ describe "Array.try_convert" do
it "sends #to_ary to the argument and raises TypeError if it's not a kind of Array" do
obj = mock("to_ary")
obj.should_receive(:to_ary).and_return(Object.new)
- -> { Array.try_convert obj }.should raise_error(TypeError, "can't convert MockObject to Array (MockObject#to_ary gives Object)")
+ -> { Array.try_convert obj }.should raise_consistent_error(TypeError, "can't convert MockObject into Array (MockObject#to_ary gives Object)")
end
it "does not rescue exceptions raised by #to_ary" do
diff --git a/spec/ruby/core/basicobject/instance_eval_spec.rb b/spec/ruby/core/basicobject/instance_eval_spec.rb
index f8d9d75059..475910e56e 100644
--- a/spec/ruby/core/basicobject/instance_eval_spec.rb
+++ b/spec/ruby/core/basicobject/instance_eval_spec.rb
@@ -284,7 +284,7 @@ describe "BasicObject#instance_eval" do
def source_code.to_str() :symbol end
a = BasicObject.new
- -> { a.instance_eval(source_code) }.should raise_error(TypeError, /can't convert Object to String/)
+ -> { a.instance_eval(source_code) }.should raise_consistent_error(TypeError, /can't convert Object into String/)
end
it "converts filename argument with #to_str method" do
@@ -303,7 +303,7 @@ describe "BasicObject#instance_eval" do
filename = Object.new
def filename.to_str() :symbol end
- -> { Object.new.instance_eval("raise", filename) }.should raise_error(TypeError, /can't convert Object to String/)
+ -> { Object.new.instance_eval("raise", filename) }.should raise_consistent_error(TypeError, /can't convert Object into String/)
end
it "converts lineno argument with #to_int method" do
@@ -322,6 +322,6 @@ describe "BasicObject#instance_eval" do
lineno = Object.new
def lineno.to_int() :symbol end
- -> { Object.new.instance_eval("raise", "file.rb", lineno) }.should raise_error(TypeError, /can't convert Object to Integer/)
+ -> { Object.new.instance_eval("raise", "file.rb", lineno) }.should raise_consistent_error(TypeError, /can't convert Object into Integer/)
end
end
diff --git a/spec/ruby/core/data/deconstruct_keys_spec.rb b/spec/ruby/core/data/deconstruct_keys_spec.rb
index df378f8b98..979d136893 100644
--- a/spec/ruby/core/data/deconstruct_keys_spec.rb
+++ b/spec/ruby/core/data/deconstruct_keys_spec.rb
@@ -106,7 +106,7 @@ describe "Data#deconstruct_keys" do
-> {
d.deconstruct_keys([key])
- }.should raise_error(TypeError, /can't convert MockObject to Integer/)
+ }.should raise_consistent_error(TypeError, /can't convert MockObject into Integer/)
end
it "raises TypeError if index is not a String, a Symbol and not convertible to Integer " do
diff --git a/spec/ruby/core/dir/for_fd_spec.rb b/spec/ruby/core/dir/for_fd_spec.rb
index 1559e1baa4..be80a2c1fe 100644
--- a/spec/ruby/core/dir/for_fd_spec.rb
+++ b/spec/ruby/core/dir/for_fd_spec.rb
@@ -54,7 +54,7 @@ platform_is_not :windows do
it "raises TypeError when value cannot be converted to Integer" do
-> {
Dir.for_fd(nil)
- }.should raise_error(TypeError, "no implicit conversion from nil to integer")
+ }.should raise_consistent_error(TypeError, "no implicit conversion of nil into Integer")
end
it "raises a SystemCallError if the file descriptor given is not valid" do
diff --git a/spec/ruby/core/hash/try_convert_spec.rb b/spec/ruby/core/hash/try_convert_spec.rb
index d359ae49d8..3932c8cdfd 100644
--- a/spec/ruby/core/hash/try_convert_spec.rb
+++ b/spec/ruby/core/hash/try_convert_spec.rb
@@ -39,7 +39,7 @@ describe "Hash.try_convert" do
it "sends #to_hash to the argument and raises TypeError if it's not a kind of Hash" do
obj = mock("to_hash")
obj.should_receive(:to_hash).and_return(Object.new)
- -> { Hash.try_convert obj }.should raise_error(TypeError, "can't convert MockObject to Hash (MockObject#to_hash gives Object)")
+ -> { Hash.try_convert obj }.should raise_consistent_error(TypeError, "can't convert MockObject into Hash (MockObject#to_hash gives Object)")
end
it "does not rescue exceptions raised by #to_hash" do
diff --git a/spec/ruby/core/integer/try_convert_spec.rb b/spec/ruby/core/integer/try_convert_spec.rb
index 8a0ca671a9..ba14a5aa7e 100644
--- a/spec/ruby/core/integer/try_convert_spec.rb
+++ b/spec/ruby/core/integer/try_convert_spec.rb
@@ -29,7 +29,7 @@ describe "Integer.try_convert" do
obj.should_receive(:to_int).and_return(Object.new)
-> {
Integer.try_convert obj
- }.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives Object)")
+ }.should raise_consistent_error(TypeError, "can't convert MockObject into Integer (MockObject#to_int gives Object)")
end
it "responds with a different error message when it raises a TypeError, depending on the type of the non-Integer object :to_int returns" do
@@ -37,7 +37,7 @@ describe "Integer.try_convert" do
obj.should_receive(:to_int).and_return("A String")
-> {
Integer.try_convert obj
- }.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives String)")
+ }.should raise_consistent_error(TypeError, "can't convert MockObject into Integer (MockObject#to_int gives String)")
end
it "does not rescue exceptions raised by #to_int" do
diff --git a/spec/ruby/core/io/lineno_spec.rb b/spec/ruby/core/io/lineno_spec.rb
index e82cdd9f17..3439a97729 100644
--- a/spec/ruby/core/io/lineno_spec.rb
+++ b/spec/ruby/core/io/lineno_spec.rb
@@ -96,7 +96,7 @@ describe "IO#lineno=" do
it "raises TypeError if cannot convert argument to Integer implicitly" do
-> { @io.lineno = "1" }.should raise_error(TypeError, 'no implicit conversion of String into Integer')
- -> { @io.lineno = nil }.should raise_error(TypeError, 'no implicit conversion from nil to integer')
+ -> { @io.lineno = nil }.should raise_consistent_error(TypeError, 'no implicit conversion of nil into Integer')
end
it "does not accept Integers that don't fit in a C int" do
diff --git a/spec/ruby/core/io/try_convert_spec.rb b/spec/ruby/core/io/try_convert_spec.rb
index a9e99de7aa..820b13ab50 100644
--- a/spec/ruby/core/io/try_convert_spec.rb
+++ b/spec/ruby/core/io/try_convert_spec.rb
@@ -38,7 +38,7 @@ describe "IO.try_convert" do
it "raises a TypeError if the object does not return an IO from #to_io" do
obj = mock("io")
obj.should_receive(:to_io).and_return("io")
- -> { IO.try_convert(obj) }.should raise_error(TypeError, "can't convert MockObject to IO (MockObject#to_io gives String)")
+ -> { IO.try_convert(obj) }.should raise_consistent_error(TypeError, "can't convert MockObject into IO (MockObject#to_io gives String)")
end
it "propagates an exception raised by #to_io" do
diff --git a/spec/ruby/core/kernel/Rational_spec.rb b/spec/ruby/core/kernel/Rational_spec.rb
index cc11a35451..7e63e0dd57 100644
--- a/spec/ruby/core/kernel/Rational_spec.rb
+++ b/spec/ruby/core/kernel/Rational_spec.rb
@@ -131,7 +131,7 @@ describe "Kernel.Rational" do
obj = Object.new
def obj.to_r; []; end
- -> { Rational(obj) }.should raise_error(TypeError, "can't convert Object to Rational (Object#to_r gives Array)")
+ -> { Rational(obj) }.should raise_consistent_error(TypeError, "can't convert Object into Rational (Object#to_r gives Array)")
end
end
diff --git a/spec/ruby/core/kernel/shared/sprintf.rb b/spec/ruby/core/kernel/shared/sprintf.rb
index 2b2c6c9b63..5ffe118035 100644
--- a/spec/ruby/core/kernel/shared/sprintf.rb
+++ b/spec/ruby/core/kernel/shared/sprintf.rb
@@ -306,13 +306,13 @@ describe :kernel_sprintf, shared: true do
it "raises TypeError if argument is not String or Integer and cannot be converted to them" do
-> {
@method.call("%c", [])
- }.should raise_error(TypeError, /no implicit conversion of Array into Integer/)
+ }.should raise_consistent_error(TypeError, /no implicit conversion of Array into Integer/)
end
it "raises TypeError if argument is nil" do
-> {
@method.call("%c", nil)
- }.should raise_error(TypeError, /no implicit conversion from nil to integer/)
+ }.should raise_consistent_error(TypeError, /no implicit conversion of nil into Integer/)
end
it "tries to convert argument to String with to_str" do
@@ -341,7 +341,7 @@ describe :kernel_sprintf, shared: true do
-> {
@method.call("%c", obj)
- }.should raise_error(TypeError, /can't convert BasicObject to String/)
+ }.should raise_consistent_error(TypeError, /can't convert BasicObject into String/)
end
it "raises TypeError if converting to Integer with to_int returns non-Integer" do
@@ -352,7 +352,7 @@ describe :kernel_sprintf, shared: true do
-> {
@method.call("%c", obj)
- }.should raise_error(TypeError, /can't convert BasicObject to Integer/)
+ }.should raise_consistent_error(TypeError, /can't convert BasicObject into Integer/)
end
end
diff --git a/spec/ruby/core/module/define_method_spec.rb b/spec/ruby/core/module/define_method_spec.rb
index c5dfc53764..a4fe4fad18 100644
--- a/spec/ruby/core/module/define_method_spec.rb
+++ b/spec/ruby/core/module/define_method_spec.rb
@@ -254,7 +254,7 @@ describe "Module#define_method" do
-> {
Class.new { define_method(obj, -> {}) }
- }.should raise_error(TypeError, /can't convert Object to String/)
+ }.should raise_consistent_error(TypeError, /can't convert Object into String/)
end
it "raises a TypeError when the given method is no Method/Proc" do
diff --git a/spec/ruby/core/module/instance_method_spec.rb b/spec/ruby/core/module/instance_method_spec.rb
index 182cdf5c54..c6bc201520 100644
--- a/spec/ruby/core/module/instance_method_spec.rb
+++ b/spec/ruby/core/module/instance_method_spec.rb
@@ -79,7 +79,7 @@ describe "Module#instance_method" do
obj = Object.new
def obj.to_str() [] end
- -> { ModuleSpecs::InstanceMeth.instance_method(obj) }.should raise_error(TypeError, /can't convert Object to String/)
+ -> { ModuleSpecs::InstanceMeth.instance_method(obj) }.should raise_consistent_error(TypeError, /can't convert Object into String/)
end
it "raises a NameError if the method has been undefined" do
diff --git a/spec/ruby/core/module/shared/class_eval.rb b/spec/ruby/core/module/shared/class_eval.rb
index 526d0a2036..b6e653a2ac 100644
--- a/spec/ruby/core/module/shared/class_eval.rb
+++ b/spec/ruby/core/module/shared/class_eval.rb
@@ -66,7 +66,7 @@ describe :module_class_eval, shared: true do
it "raises a TypeError when the given filename can't be converted to string using to_str" do
(file = mock('123')).should_receive(:to_str).and_return(123)
- -> { ModuleSpecs.send(@method, "1+1", file) }.should raise_error(TypeError, /can't convert MockObject to String/)
+ -> { ModuleSpecs.send(@method, "1+1", file) }.should raise_consistent_error(TypeError, /can't convert MockObject into String/)
end
it "converts non string eval-string to string using to_str" do
@@ -85,7 +85,7 @@ describe :module_class_eval, shared: true do
-> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError, "no implicit conversion of MockObject into String")
(o = mock('123')).should_receive(:to_str).and_return(123)
- -> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError, /can't convert MockObject to String/)
+ -> { ModuleSpecs.send(@method, o) }.should raise_consistent_error(TypeError, /can't convert MockObject into String/)
end
it "raises an ArgumentError when no arguments and no block are given" do
diff --git a/spec/ruby/core/process/detach_spec.rb b/spec/ruby/core/process/detach_spec.rb
index f13bda1f5d..f5f3b263f5 100644
--- a/spec/ruby/core/process/detach_spec.rb
+++ b/spec/ruby/core/process/detach_spec.rb
@@ -75,7 +75,7 @@ describe "Process.detach" do
pid = MockObject.new('mock-enumerable')
pid.should_receive(:to_int).and_return(:symbol)
- -> { Process.detach(pid) }.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives Symbol)")
+ -> { Process.detach(pid) }.should raise_consistent_error(TypeError, "can't convert MockObject into Integer (MockObject#to_int gives Symbol)")
end
end
end
diff --git a/spec/ruby/core/queue/initialize_spec.rb b/spec/ruby/core/queue/initialize_spec.rb
index 592fbe2487..6b9e6b7fa9 100644
--- a/spec/ruby/core/queue/initialize_spec.rb
+++ b/spec/ruby/core/queue/initialize_spec.rb
@@ -55,6 +55,6 @@ describe "Queue#initialize" do
enumerable = MockObject.new('mock-enumerable')
enumerable.should_receive(:to_a).and_return("string")
- -> { Queue.new(enumerable) }.should raise_error(TypeError, "can't convert MockObject to Array (MockObject#to_a gives String)")
+ -> { Queue.new(enumerable) }.should raise_consistent_error(TypeError, "can't convert MockObject into Array (MockObject#to_a gives String)")
end
end
diff --git a/spec/ruby/core/regexp/shared/new.rb b/spec/ruby/core/regexp/shared/new.rb
index 12c3d7c9c2..7b0f12d623 100644
--- a/spec/ruby/core/regexp/shared/new.rb
+++ b/spec/ruby/core/regexp/shared/new.rb
@@ -46,7 +46,7 @@ describe :regexp_new_non_string_or_regexp, shared: true do
obj = Object.new
def obj.to_str() [] end
- -> { Regexp.send(@method, obj) }.should raise_error(TypeError, /can't convert Object to String/)
+ -> { Regexp.send(@method, obj) }.should raise_consistent_error(TypeError, /can't convert Object into String/)
end
end
diff --git a/spec/ruby/core/regexp/try_convert_spec.rb b/spec/ruby/core/regexp/try_convert_spec.rb
index e775dbe971..44a6fead83 100644
--- a/spec/ruby/core/regexp/try_convert_spec.rb
+++ b/spec/ruby/core/regexp/try_convert_spec.rb
@@ -22,6 +22,6 @@ describe "Regexp.try_convert" do
it "raises a TypeError if the object does not return an Regexp from #to_regexp" do
obj = mock("regexp")
obj.should_receive(:to_regexp).and_return("string")
- -> { Regexp.try_convert(obj) }.should raise_error(TypeError, "can't convert MockObject to Regexp (MockObject#to_regexp gives String)")
+ -> { Regexp.try_convert(obj) }.should raise_consistent_error(TypeError, "can't convert MockObject into Regexp (MockObject#to_regexp gives String)")
end
end
diff --git a/spec/ruby/core/string/try_convert_spec.rb b/spec/ruby/core/string/try_convert_spec.rb
index 72ce5dd8b2..7019f1fc2a 100644
--- a/spec/ruby/core/string/try_convert_spec.rb
+++ b/spec/ruby/core/string/try_convert_spec.rb
@@ -39,7 +39,7 @@ describe "String.try_convert" do
it "sends #to_str to the argument and raises TypeError if it's not a kind of String" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return(Object.new)
- -> { String.try_convert obj }.should raise_error(TypeError, "can't convert MockObject to String (MockObject#to_str gives Object)")
+ -> { String.try_convert obj }.should raise_consistent_error(TypeError, "can't convert MockObject into String (MockObject#to_str gives Object)")
end
it "does not rescue exceptions raised by #to_str" do
diff --git a/spec/ruby/core/struct/deconstruct_keys_spec.rb b/spec/ruby/core/struct/deconstruct_keys_spec.rb
index e16b50f930..0360a4b194 100644
--- a/spec/ruby/core/struct/deconstruct_keys_spec.rb
+++ b/spec/ruby/core/struct/deconstruct_keys_spec.rb
@@ -106,7 +106,7 @@ describe "Struct#deconstruct_keys" do
-> {
s.deconstruct_keys([key])
- }.should raise_error(TypeError, /can't convert MockObject to Integer/)
+ }.should raise_consistent_error(TypeError, /can't convert MockObject into Integer/)
end
it "raises TypeError if index is not a String, a Symbol and not convertible to Integer" do
diff --git a/spec/ruby/language/send_spec.rb b/spec/ruby/language/send_spec.rb
index 5d6340ffc5..c60381cf55 100644
--- a/spec/ruby/language/send_spec.rb
+++ b/spec/ruby/language/send_spec.rb
@@ -112,7 +112,7 @@ describe "Invoking a method" do
-> {
specs.makeproc(&o)
- }.should raise_error(TypeError, "can't convert LangSendSpecs::RawToProc to Proc (LangSendSpecs::RawToProc#to_proc gives Integer)")
+ }.should raise_consistent_error(TypeError, "can't convert LangSendSpecs::RawToProc into Proc (LangSendSpecs::RawToProc#to_proc gives Integer)")
end
it "raises TypeError if block object isn't a Proc and doesn't respond to `to_proc`" do
diff --git a/spec/ruby/shared/queue/deque.rb b/spec/ruby/shared/queue/deque.rb
index a154da6274..fbd00143f8 100644
--- a/spec/ruby/shared/queue/deque.rb
+++ b/spec/ruby/shared/queue/deque.rb
@@ -105,11 +105,11 @@ describe :queue_deq, shared: true do
q = @object.call
-> {
q.send(@method, timeout: "1")
- }.should raise_error(TypeError, "no implicit conversion to float from string")
+ }.should raise_consistent_error(TypeError, "no implicit conversion of String into Float")
-> {
q.send(@method, timeout: false)
- }.should raise_error(TypeError, "no implicit conversion to float from false")
+ }.should raise_consistent_error(TypeError, "no implicit conversion of false into Float")
end
it "raise ArgumentError if non_block = true is passed too" do
diff --git a/spec/ruby/shared/sizedqueue/enque.rb b/spec/ruby/shared/sizedqueue/enque.rb
index 6804af3fb3..bab4c407e1 100644
--- a/spec/ruby/shared/sizedqueue/enque.rb
+++ b/spec/ruby/shared/sizedqueue/enque.rb
@@ -90,11 +90,11 @@ describe :sizedqueue_enq, shared: true do
q = @object.call(1)
-> {
q.send(@method, 2, timeout: "1")
- }.should raise_error(TypeError, "no implicit conversion to float from string")
+ }.should raise_consistent_error(TypeError, "no implicit conversion of String into Float")
-> {
q.send(@method, 2, timeout: false)
- }.should raise_error(TypeError, "no implicit conversion to float from false")
+ }.should raise_consistent_error(TypeError, "no implicit conversion of false into Float")
end
it "raise ArgumentError if non_block = true is passed too" do
diff --git a/spec/ruby/shared/types/rb_num2dbl_fails.rb b/spec/ruby/shared/types/rb_num2dbl_fails.rb
index ec7cc11986..4d4856fa6c 100644
--- a/spec/ruby/shared/types/rb_num2dbl_fails.rb
+++ b/spec/ruby/shared/types/rb_num2dbl_fails.rb
@@ -7,11 +7,11 @@
describe :rb_num2dbl_fails, shared: true do
it "fails if string is provided" do
- -> { @object.call("123") }.should raise_error(TypeError, "no implicit conversion to float from string")
+ -> { @object.call("123") }.should raise_consistent_error(TypeError, "no implicit conversion of String into Float")
end
it "fails if boolean is provided" do
- -> { @object.call(true) }.should raise_error(TypeError, "no implicit conversion to float from true")
- -> { @object.call(false) }.should raise_error(TypeError, "no implicit conversion to float from false")
+ -> { @object.call(true) }.should raise_consistent_error(TypeError, "no implicit conversion of true into Float")
+ -> { @object.call(false) }.should raise_consistent_error(TypeError, "no implicit conversion of false into Float")
end
end
diff --git a/test/error_highlight/test_error_highlight.rb b/test/error_highlight/test_error_highlight.rb
index ec39b1c4db..5f664de502 100644
--- a/test/error_highlight/test_error_highlight.rb
+++ b/test/error_highlight/test_error_highlight.rb
@@ -1085,10 +1085,11 @@ nil can't be coerced into Integer (TypeError)
end
end
+ OF_NIL_INTO_INTEGER = RUBY_VERSION < "4.1." ? "from nil to integer" : "of nil into Integer"
def test_args_CALL_2
v = []
assert_error_message(TypeError, <<~END) do
-no implicit conversion from nil to integer (TypeError)
+no implicit conversion #{OF_NIL_INTO_INTEGER} (TypeError)
v[nil]
^^^
@@ -1115,7 +1116,7 @@ undefined method `[]=' for #{ recv }
def test_args_ATTRASGN_2
v = []
assert_error_message(TypeError, <<~END) do
-no implicit conversion from nil to integer (TypeError)
+no implicit conversion #{OF_NIL_INTO_INTEGER} (TypeError)
v [nil] = 1
^^^^^^^^
@@ -1177,7 +1178,7 @@ no implicit conversion of Symbol into String (TypeError)
v = []
assert_error_message(TypeError, <<~END) do
-no implicit conversion from nil to integer (TypeError)
+no implicit conversion #{OF_NIL_INTO_INTEGER} (TypeError)
v [nil] += 42
^^^^^^^^^^
diff --git a/test/ruby/test_exception.rb b/test/ruby/test_exception.rb
index 31e5aa9f6b..4365150a13 100644
--- a/test/ruby/test_exception.rb
+++ b/test/ruby/test_exception.rb
@@ -1542,13 +1542,13 @@ $stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status|
def a.to_a = 1
def a.to_hash = 1
def a.to_proc = 1
- assert_raise_with_message(TypeError, "can't convert TestException::Ex to Array (TestException::Ex#to_a gives Integer)") do
+ assert_raise_with_message(TypeError, "can't convert TestException::Ex into Array (TestException::Ex#to_a gives Integer)") do
x(*a)
end
- assert_raise_with_message(TypeError, "can't convert TestException::Ex to Hash (TestException::Ex#to_hash gives Integer)") do
+ assert_raise_with_message(TypeError, "can't convert TestException::Ex into Hash (TestException::Ex#to_hash gives Integer)") do
x(**a)
end
- assert_raise_with_message(TypeError, "can't convert TestException::Ex to Proc (TestException::Ex#to_proc gives Integer)") do
+ assert_raise_with_message(TypeError, "can't convert TestException::Ex into Proc (TestException::Ex#to_proc gives Integer)") do
x(&a)
end
end
diff --git a/test/ruby/test_integer.rb b/test/ruby/test_integer.rb
index f9bf4fa20c..c3d9d311c8 100644
--- a/test/ruby/test_integer.rb
+++ b/test/ruby/test_integer.rb
@@ -751,7 +751,7 @@ class TestInteger < Test::Unit::TestCase
o = Object.new
def o.to_int; Object.new; end
- assert_raise_with_message(TypeError, /can't convert Object to Integer/) {Integer.try_convert(o)}
+ assert_raise_with_message(TypeError, /can't convert Object into Integer/) {Integer.try_convert(o)}
end
def test_ceildiv
diff --git a/time.c b/time.c
index acc20d2c97..c3bda3f6af 100644
--- a/time.c
+++ b/time.c
@@ -36,6 +36,7 @@
#include "internal/array.h"
#include "internal/hash.h"
#include "internal/compar.h"
+#include "internal/error.h"
#include "internal/numeric.h"
#include "internal/rational.h"
#include "internal/string.h"
@@ -564,8 +565,7 @@ NORETURN(static void num_exact_fail(VALUE v));
static void
num_exact_fail(VALUE v)
{
- rb_raise(rb_eTypeError, "can't convert %"PRIsVALUE" into an exact number",
- rb_obj_class(v));
+ rb_cant_convert(v, "an exact number");
}
static VALUE
@@ -2924,8 +2924,7 @@ time_timespec(VALUE num, int interval)
t.tv_nsec = NUM2LONG(f);
}
else {
- rb_raise(rb_eTypeError, "can't convert %"PRIsVALUE" into %s",
- rb_obj_class(num), tstr);
+ rb_cant_convert(num, tstr);
}
}
return t;
diff --git a/vm_args.c b/vm_args.c
index 458710e59e..90a18ee8df 100644
--- a/vm_args.c
+++ b/vm_args.c
@@ -1052,15 +1052,10 @@ vm_to_proc(VALUE proc)
if (NIL_P(b) || !rb_obj_is_proc(b)) {
if (me) {
- VALUE cname = rb_obj_class(proc);
- rb_raise(rb_eTypeError,
- "can't convert %"PRIsVALUE" to Proc (%"PRIsVALUE"#to_proc gives %"PRIsVALUE")",
- cname, cname, rb_obj_class(b));
+ rb_cant_convert_invalid_return(proc, "Proc", "to_proc", b);
}
else {
- rb_raise(rb_eTypeError,
- "no implicit conversion of %s into Proc",
- rb_obj_classname(proc));
+ rb_no_implicit_conversion(proc, "Proc");
}
}
return b;