Project

General

Profile

Feature #14111 » add_receiver_and_method_name_to_argument_error_for_application_code_2.diff

esjee (SJ Stoker), 12/01/2017 10:59 PM

View differences:

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);
}
}
(2-2/3)