diff --git a/include/natalie/env.hpp b/include/natalie/env.hpp index d69d20b5a3..3f8f0eaa67 100644 --- a/include/natalie/env.hpp +++ b/include/natalie/env.hpp @@ -81,15 +81,7 @@ class Env : public Cell { [[noreturn]] void raise_name_error(StringObject *name, String); [[noreturn]] void raise_not_comparable_error(Value lhs, Value rhs); - // Old error message style, e.g.: - // - no implicit conversion from nil to string - // - no implicit conversion of Integer into String - [[noreturn]] void raise_type_error(Value obj, const char *expected); - - // New error message style, e.g.: - // - no implicit conversion of nil into String - // - no implicit conversion of Integer into String - [[noreturn]] void raise_type_error2(Value obj, const char *expected); + [[noreturn]] void raise_type_error(Value obj, const char *expected, bool = false); template [[noreturn]] void raise_name_error(SymbolObject *name, const char *format, Args... args) { diff --git a/include/natalie/value.hpp b/include/natalie/value.hpp index 2c4c6081dd..62f32ce22f 100644 --- a/include/natalie/value.hpp +++ b/include/natalie/value.hpp @@ -94,15 +94,7 @@ class Value { ClassObject *singleton_class() const; ClassObject *singleton_class(Env *); - // Old error message style, e.g.: - // - no implicit conversion from nil to string - // - no implicit conversion of Integer into String - StringObject *to_str(Env *env); - - // New error message style, e.g.: - // - no implicit conversion of nil into String - // - no implicit conversion of Integer into String - StringObject *to_str2(Env *env); + StringObject *to_str(Env *env, bool = false); Integer integer() const; Integer integer_or_raise(Env *) const; diff --git a/lib/cgi/escape.rb b/lib/cgi/escape.rb index 90b1ac0ebb..20c6e30027 100644 --- a/lib/cgi/escape.rb +++ b/lib/cgi/escape.rb @@ -50,7 +50,7 @@ def unescape(string, encoding = @@accept_charset) # # => "%27Stop%21%27%20said%20Fred" def escapeURIComponent(string) # NATALIE ruby converts this in a c extension - __inline__ 'string_var = string_var.to_str2(env)' + __inline__ 'string_var = string_var.to_str(env, /*mri_variant_error_msg*/ true)' # END NATALIE encoding = string.encoding buffer = string.b @@ -66,7 +66,7 @@ def escapeURIComponent(string) # # => "'Stop!'+said Fred" def unescapeURIComponent(string, encoding = @@accept_charset) # NATALIE ruby converts this in a c extension - __inline__ 'string_var = string_var.to_str2(env)' + __inline__ 'string_var = string_var.to_str(env, /*mri_variant_error_msg*/ true)' # END NATALIE str = string.b str.gsub!(/((?:%[0-9a-fA-F]{2})+)/) do |m| diff --git a/src/env.cpp b/src/env.cpp index 576189112e..123a6ddeb5 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -223,27 +223,25 @@ void Env::raise_not_comparable_error(Value lhs, Value rhs) { raise("ArgumentError", std::move(message)); } -void Env::raise_type_error(const Value obj, const char *expected) { +// The origin of the mri_variant_error_msg has been lost in the mists of time... +// But spec depends on them +void Env::raise_type_error(const Value obj, const char *expected, bool mri_variant_error_msg) { if (obj.is_nil()) { - auto lowercase_expected = StringObject::create(expected); - lowercase_expected->downcase_in_place(this); - raise("TypeError", "no implicit conversion from nil to {}", lowercase_expected->string()); - } else { - raise("TypeError", "no implicit conversion of {} into {}", obj.klass()->inspect_module(), expected); + if (mri_variant_error_msg) { + raise("TypeError", "no implicit conversion of nil into {}", expected); + } else { + auto lowercase_expected = StringObject::create(expected); + lowercase_expected->downcase_in_place(this); + raise("TypeError", "no implicit conversion from nil to {}", lowercase_expected->string()); + } } -} - -// This is the same as Env::raise_type_error, but with more consistent error messages. -// We need both methods because CRuby is inconsistent. :-( -void Env::raise_type_error2(const Value obj, const char *expected) { - if (obj.is_nil()) - raise("TypeError", "no implicit conversion of nil into {}", expected); - else if (obj.is_true()) - raise("TypeError", "no implicit conversion of true into {}", expected); - else if (obj.is_false()) - raise("TypeError", "no implicit conversion of false into {}", expected); - else - raise("TypeError", "no implicit conversion of {} into {}", obj.klass()->inspect_module(), expected); + if (mri_variant_error_msg) { + if (obj.is_true()) + raise("TypeError", "no implicit conversion of true into {}", expected); + if (obj.is_false()) + raise("TypeError", "no implicit conversion of false into {}", expected); + } + raise("TypeError", "no implicit conversion of {} into {}", obj.klass()->inspect_module(), expected); } bool Env::has_catch(Value value) const { diff --git a/src/string_object.cpp b/src/string_object.cpp index e3e02b478b..c54c266430 100644 --- a/src/string_object.cpp +++ b/src/string_object.cpp @@ -756,7 +756,7 @@ Value StringObject::byteindex(Env *env, Value needle_obj, Optional offset if (needle_obj.is_regexp()) return byteindex_regexp_needle(env, this, needle_obj.as_regexp(), offset); - auto needle = needle_obj.to_str2(env); + auto needle = needle_obj.to_str(env, /*mri_variant_error_msg*/ true); return byteindex_string_needle(env, this, needle, offset); } @@ -773,7 +773,7 @@ Value StringObject::byterindex(Env *env, Value needle_obj, Optional offse if (needle_obj.is_regexp()) return byteindex_regexp_needle(env, this, needle_obj.as_regexp(), offset, true); - auto needle = needle_obj.to_str2(env); + auto needle = needle_obj.to_str(env, /*mri_variant_error_msg*/ true); return byteindex_string_needle(env, this, needle, offset, true); } diff --git a/src/value.cpp b/src/value.cpp index 5f807a9366..f038a4a950 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -92,35 +92,15 @@ ClassObject *Value::singleton_class(Env *env) { return Object::singleton_class(env, *this); } -StringObject *Value::to_str(Env *env) { +// The origin of the mri_variant_error_msg has been lost in the mists of time... +// But spec depends on them +StringObject *Value::to_str(Env *env, bool mri_variant_error_msg) { if (is_string()) return as_string(); auto to_str = "to_str"_s; if (!respond_to(env, to_str)) - env->raise_type_error(*this, "String"); - - auto result = send(env, to_str); - - if (result.is_string()) - return result.as_string(); - - env->raise( - "TypeError", "can't convert {} to String ({}#to_str gives {})", - klass()->inspect_module(), - klass()->inspect_module(), - result.klass()->inspect_module()); -} - -// This is just like Value::to_str, but it raises more consistent error messages. -// We still need the old error messages because CRuby is inconsistent. :-( -StringObject *Value::to_str2(Env *env) { - if (is_string()) - return as_string(); - - auto to_str = "to_str"_s; - if (!respond_to(env, to_str)) - env->raise_type_error2(*this, "String"); + env->raise_type_error(*this, "String", mri_variant_error_msg); auto result = send(env, to_str);