diff options
Diffstat (limited to 'vm_args.c')
| -rw-r--r-- | vm_args.c | 70 |
1 files changed, 51 insertions, 19 deletions
@@ -1,6 +1,6 @@ /********************************************************************** - vm_args.c - process method call arguments. + vm_args.c - process method call arguments. Included into vm.c. $Author$ @@ -12,6 +12,8 @@ NORETURN(static void raise_argument_error(rb_execution_context_t *ec, const rb_i NORETURN(static void argument_arity_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, 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 rb_callable_method_entry_t *cme, const char *error, const VALUE keys)); VALUE rb_keyword_error_new(const char *error, VALUE keys); /* class.c */ +static VALUE set_error_backtrace(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const VALUE exc); + static VALUE method_missing(rb_execution_context_t *ec, VALUE obj, ID id, int argc, const VALUE *argv, enum method_missing_reason call_status, int kw_splat); const rb_callable_method_entry_t *rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me); @@ -318,8 +320,6 @@ args_setup_kw_parameters_lookup(const ID key, VALUE *ptr, const VALUE *const pas return FALSE; } -#define KW_SPECIFIED_BITS_MAX (32-1) /* TODO: 32 -> Fixnum's max bits */ - static void args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *const iseq, const rb_callable_method_entry_t *cme, VALUE *const passed_values, const int passed_keyword_len, const VALUE *const passed_keywords, @@ -355,7 +355,7 @@ args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *cons if (UNDEF_P(default_values[di])) { locals[i] = Qnil; - if (LIKELY(i < KW_SPECIFIED_BITS_MAX)) { + if (LIKELY(i < VM_KW_SPECIFIED_BITS_MAX)) { unspecified_bits |= 0x01 << di; } else { @@ -364,7 +364,7 @@ args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *cons int j; unspecified_bits_value = rb_hash_new(); - for (j=0; j<KW_SPECIFIED_BITS_MAX; j++) { + for (j=0; j<VM_KW_SPECIFIED_BITS_MAX; j++) { if (unspecified_bits & (0x01 << j)) { rb_hash_aset(unspecified_bits_value, INT2FIX(j), Qtrue); } @@ -450,7 +450,7 @@ args_setup_kw_parameters_from_kwsplat(rb_execution_context_t *const ec, const rb if (UNDEF_P(default_values[di])) { locals[i] = Qnil; - if (LIKELY(i < KW_SPECIFIED_BITS_MAX)) { + if (LIKELY(i < VM_KW_SPECIFIED_BITS_MAX)) { unspecified_bits |= 0x01 << di; } else { @@ -459,7 +459,7 @@ args_setup_kw_parameters_from_kwsplat(rb_execution_context_t *const ec, const rb int j; unspecified_bits_value = rb_hash_new(); - for (j=0; j<KW_SPECIFIED_BITS_MAX; j++) { + for (j=0; j<VM_KW_SPECIFIED_BITS_MAX; j++) { if (unspecified_bits & (0x01 << j)) { rb_hash_aset(unspecified_bits_value, INT2FIX(j), Qtrue); } @@ -640,12 +640,26 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co given_argc == ISEQ_BODY(iseq)->param.lead_num + (kw_flag ? 2 : 1) && !ISEQ_BODY(iseq)->param.flags.has_opt && !ISEQ_BODY(iseq)->param.flags.has_post && - !ISEQ_BODY(iseq)->param.flags.ruby2_keywords && - (!kw_flag || - !ISEQ_BODY(iseq)->param.flags.has_kw || - !ISEQ_BODY(iseq)->param.flags.has_kwrest || - !ISEQ_BODY(iseq)->param.flags.accepts_no_kwarg)) { - args->rest_dupped = true; + !ISEQ_BODY(iseq)->param.flags.ruby2_keywords) { + if (kw_flag) { + if (ISEQ_BODY(iseq)->param.flags.has_kw || + ISEQ_BODY(iseq)->param.flags.has_kwrest) { + args->rest_dupped = true; + } + else if (kw_flag & VM_CALL_KW_SPLAT) { + VALUE kw_hash = locals[args->argc - 1]; + if (kw_hash == Qnil || + (RB_TYPE_P(kw_hash, T_HASH) && RHASH_EMPTY_P(kw_hash))) { + args->rest_dupped = true; + } + } + + } + else if (!ISEQ_BODY(iseq)->param.flags.has_kw && + !ISEQ_BODY(iseq)->param.flags.has_kwrest && + !ISEQ_BODY(iseq)->param.flags.accepts_no_kwarg) { + args->rest_dupped = true; + } } } @@ -953,7 +967,15 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co argument_kw_error(ec, iseq, cme, "unknown", rb_hash_keys(keyword_hash)); } - if (ISEQ_BODY(iseq)->param.flags.has_block) { + if (ISEQ_BODY(iseq)->param.flags.accepts_no_block) { + VALUE given_block; + args_setup_block_parameter(ec, calling, &given_block); + if (!NIL_P(given_block)) { + VALUE exc = rb_exc_new_cstr(rb_eArgError, "no block accepted"); + rb_exc_raise(set_error_backtrace(ec, iseq, cme, exc)); + } + } + else if (ISEQ_BODY(iseq)->param.flags.has_block) { if (ISEQ_BODY(iseq)->local_iseq == iseq) { /* Do nothing */ } @@ -975,8 +997,8 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co return opt_pc; } -static void -raise_argument_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const VALUE exc) +static VALUE +set_error_backtrace(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const VALUE exc) { VALUE at; @@ -994,6 +1016,13 @@ raise_argument_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb rb_ivar_set(exc, idBt_locations, at); rb_exc_set_backtrace(exc, at); + return exc; +} + +static void +raise_argument_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const VALUE exc) +{ + set_error_backtrace(ec, iseq, cme, exc); rb_exc_raise(exc); } @@ -1045,9 +1074,12 @@ vm_to_proc(VALUE proc) } if (NIL_P(b) || !rb_obj_is_proc(b)) { - rb_raise(rb_eTypeError, - "wrong argument type %s (expected Proc)", - rb_obj_classname(proc)); + if (me) { + rb_cant_convert_invalid_return(proc, "Proc", "to_proc", b); + } + else { + rb_no_implicit_conversion(proc, "Proc"); + } } return b; } |
