Feature #14111 » add_receiver_and_method_name_to_argument_error_for_application_code_2.diff
spec/ruby/core/exception/arguments_spec.rb | ||
---|---|---|
require File.expand_path('../../../spec_helper', __FILE__)
|
||
describe "ArgumentError" do
|
||
class ArgumentErrorDummyClass
|
||
def foo(a,b,c:)
|
||
end
|
||
def foo_kw(a:)
|
||
end
|
||
end
|
||
it "is a subclass of StandardError" do
|
||
StandardError.should be_ancestor_of(ArgumentError)
|
||
end
|
||
... | ... | |
it "gives its own class name as message if it has no message" do
|
||
ArgumentError.new.message.should == "ArgumentError"
|
||
end
|
||
describe "arity error" do
|
||
it "includes receiver and method name when raised by application code" do
|
||
exc = begin
|
||
ArgumentErrorDummyClass.new.foo(3)
|
||
rescue => exc
|
||
exc
|
||
end
|
||
exc.instance_variable_get('@receiver').should_not be_nil
|
||
exc.instance_variable_get('@receiver').should.class === ArgumentErrorDummyClass
|
||
exc.instance_variable_get('@method_name').should == 'foo'
|
||
end
|
||
end
|
||
describe "kw error" do
|
||
it "includes receiver and method name when raised by application code" do
|
||
exc = begin
|
||
ArgumentErrorDummyClass.new.foo_kw()
|
||
rescue => exc
|
||
exc
|
||
end
|
||
exc.instance_variable_get('@receiver').should_not be_nil
|
||
exc.instance_variable_get('@receiver').should.class === ArgumentErrorDummyClass
|
||
exc.instance_variable_get('@method_name').should == 'foo'
|
||
end
|
||
end
|
||
end
|
vm_args.c | ||
---|---|---|
**********************************************************************/
|
||
NORETURN(static void raise_argument_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const VALUE exc));
|
||
NORETURN(static void argument_arity_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const int miss_argc, const int min_argc, const int max_argc));
|
||
NORETURN(static void argument_kw_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const char *error, const VALUE keys));
|
||
NORETURN(static void argument_arity_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, struct rb_calling_info *calling, const int miss_argc, const int min_argc, const int max_argc));
|
||
NORETURN(static void argument_kw_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, struct rb_calling_info *calling, const char *error, const VALUE keys));
|
||
VALUE rb_keyword_error_new(const char *error, VALUE keys); /* class.c */
|
||
static VALUE method_missing(VALUE obj, ID id, int argc, const VALUE *argv,
|
||
enum method_missing_reason call_status);
|
||
... | ... | |
static void
|
||
args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *const iseq,
|
||
VALUE *const passed_values, const int passed_keyword_len, const VALUE *const passed_keywords,
|
||
struct rb_calling_info *calling, VALUE *const passed_values,
|
||
const int passed_keyword_len, const VALUE *const passed_keywords,
|
||
VALUE *const locals)
|
||
{
|
||
const ID *acceptable_keywords = iseq->body->param.keyword->table;
|
||
... | ... | |
}
|
||
}
|
||
if (missing) argument_kw_error(ec, iseq, "missing", missing);
|
||
if (missing) argument_kw_error(ec, iseq, calling, "missing", missing);
|
||
for (di=0; i<key_num; i++, di++) {
|
||
if (args_setup_kw_parameters_lookup(acceptable_keywords[i], &locals[i], passed_keywords, passed_values, passed_keyword_len)) {
|
||
... | ... | |
else {
|
||
if (found != passed_keyword_len) {
|
||
VALUE keys = make_unknown_kw_hash(passed_keywords, passed_keyword_len, passed_values);
|
||
argument_kw_error(ec, iseq, "unknown", keys);
|
||
argument_kw_error(ec, iseq, calling, "unknown", keys);
|
||
}
|
||
}
|
||
... | ... | |
args_extend(args, min_argc);
|
||
}
|
||
else {
|
||
argument_arity_error(ec, iseq, given_argc, min_argc, max_argc);
|
||
argument_arity_error(ec, iseq, calling, given_argc, min_argc, max_argc);
|
||
}
|
||
}
|
||
}
|
||
... | ... | |
given_argc = max_argc;
|
||
}
|
||
else {
|
||
argument_arity_error(ec, iseq, given_argc, min_argc, max_argc);
|
||
argument_arity_error(ec, iseq, calling, given_argc, min_argc, max_argc);
|
||
}
|
||
}
|
||
... | ... | |
if (args->kw_argv != NULL) {
|
||
const struct rb_call_info_kw_arg *kw_arg = args->kw_arg;
|
||
args_setup_kw_parameters(ec, iseq, args->kw_argv, kw_arg->keyword_len, kw_arg->keywords, klocals);
|
||
args_setup_kw_parameters(ec, iseq, calling, args->kw_argv, kw_arg->keyword_len, kw_arg->keywords, klocals);
|
||
}
|
||
else if (!NIL_P(keyword_hash)) {
|
||
int kw_len = rb_long2int(RHASH_SIZE(keyword_hash));
|
||
... | ... | |
arg.argc = 0;
|
||
rb_hash_foreach(keyword_hash, fill_keys_values, (VALUE)&arg);
|
||
VM_ASSERT(arg.argc == kw_len);
|
||
args_setup_kw_parameters(ec, iseq, arg.vals, kw_len, arg.keys, klocals);
|
||
args_setup_kw_parameters(ec, iseq, calling, arg.vals, kw_len, arg.keys, klocals);
|
||
}
|
||
else {
|
||
VM_ASSERT(args_argc(args) == 0);
|
||
args_setup_kw_parameters(ec, iseq, NULL, 0, NULL, klocals);
|
||
args_setup_kw_parameters(ec, iseq, calling, NULL, 0, NULL, klocals);
|
||
}
|
||
}
|
||
else if (iseq->body->param.flags.has_kwrest) {
|
||
args_setup_kw_rest_parameter(keyword_hash, locals + iseq->body->param.keyword->rest_start);
|
||
}
|
||
else if (!NIL_P(keyword_hash) && RHASH_SIZE(keyword_hash) > 0) {
|
||
argument_kw_error(ec, iseq, "unknown", rb_hash_keys(keyword_hash));
|
||
argument_kw_error(ec, iseq, calling, "unknown", rb_hash_keys(keyword_hash));
|
||
}
|
||
if (iseq->body->param.flags.has_block) {
|
||
... | ... | |
}
|
||
static void
|
||
argument_arity_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const int miss_argc, const int min_argc, const int max_argc)
|
||
argument_arity_error(rb_execution_context_t *ec, const rb_iseq_t *iseq,
|
||
struct rb_calling_info *calling,
|
||
const int miss_argc, const int min_argc, const int max_argc)
|
||
{
|
||
VALUE exc = rb_arity_error_new(miss_argc, min_argc, max_argc);
|
||
if (iseq->body->param.flags.has_kw) {
|
||
... | ... | |
RSTRING_PTR(mesg)[RSTRING_LEN(mesg)-1] = ')';
|
||
}
|
||
}
|
||
rb_iv_set(exc, "@receiver", calling->recv);
|
||
rb_iv_set(exc, "@method_name", rb_iseq_method_name(iseq));
|
||
raise_argument_error(ec, iseq, exc);
|
||
}
|
||
static void
|
||
argument_kw_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const char *error, const VALUE keys)
|
||
argument_kw_error(rb_execution_context_t *ec, const rb_iseq_t *iseq,
|
||
struct rb_calling_info *calling, const char *error,
|
||
const VALUE keys)
|
||
{
|
||
raise_argument_error(ec, iseq, rb_keyword_error_new(error, keys));
|
||
VALUE exc = rb_keyword_error_new(error, keys);
|
||
rb_iv_set(exc, "@receiver", calling->recv);
|
||
rb_iv_set(exc, "@method_name", rb_iseq_method_name(iseq));
|
||
raise_argument_error(ec, iseq, exc);
|
||
}
|
||
static inline void
|
vm_insnhelper.c | ||
---|---|---|
CALLER_SETUP_ARG(cfp, calling, ci); /* splat arg */
|
||
if (calling->argc != iseq->body->param.lead_num) {
|
||
argument_arity_error(ec, iseq, calling->argc, iseq->body->param.lead_num, iseq->body->param.lead_num);
|
||
argument_arity_error(ec, iseq, calling, calling->argc, iseq->body->param.lead_num, iseq->body->param.lead_num);
|
||
}
|
||
CI_SET_FASTPATH(cc, vm_call_iseq_setup_func(ci, param_size, local_size),
|
||
... | ... | |
}
|
||
}
|
||
else {
|
||
argument_arity_error(ec, iseq, calling->argc, iseq->body->param.lead_num, iseq->body->param.lead_num);
|
||
argument_arity_error(ec, iseq, calling, calling->argc, iseq->body->param.lead_num, iseq->body->param.lead_num);
|
||
}
|
||
}
|
||