summaryrefslogtreecommitdiff
path: root/vm_args.c
diff options
context:
space:
mode:
Diffstat (limited to 'vm_args.c')
-rw-r--r--vm_args.c70
1 files changed, 51 insertions, 19 deletions
diff --git a/vm_args.c b/vm_args.c
index 44be6f54c5..3d67c6540a 100644
--- a/vm_args.c
+++ b/vm_args.c
@@ -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;
}