aboutsummaryrefslogtreecommitdiffstats
path: root/vm_insnhelper.c
diff options
context:
space:
mode:
authorJeremy Evans <code@jeremyevans.net>2019-10-04 12:51:57 -0700
committerJeremy Evans <code@jeremyevans.net>2020-01-02 18:40:45 -0800
commitbeae6cbf0fd8b6619e5212552de98022d4c4d4d4 (patch)
treea926f619ed39569df4e93ec31157acdb78796379 /vm_insnhelper.c
parent8ba261c7546e3cd12ff6870bb41dd0a0bee32ba8 (diff)
downloadruby-beae6cbf0fd8b6619e5212552de98022d4c4d4d4.tar.gz
Fully separate positional arguments and keyword arguments
This removes the warnings added in 2.7, and changes the behavior so that a final positional hash is not treated as keywords or vice-versa. To handle the arg_setup_block splat case correctly with keyword arguments, we need to check if we are taking a keyword hash. That case didn't have a test, but it affects real-world code, so add a test for it. This removes rb_empty_keyword_given_p() and related code, as that is not needed in Ruby 3. The empty keyword case is the same as the no keyword case in Ruby 3. This changes rb_scan_args to implement keyword argument separation for C functions when the : character is used. For backwards compatibility, it returns a duped hash. This is a bad idea for performance, but not duping the hash breaks at least Enumerator::ArithmeticSequence#inspect. Instead of having RB_PASS_CALLED_KEYWORDS be a number, simplify the code by just making it be rb_keyword_given_p().
Diffstat (limited to 'vm_insnhelper.c')
-rw-r--r--vm_insnhelper.c45
1 files changed, 7 insertions, 38 deletions
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 8cc47e15af..d69340b071 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -2486,9 +2486,8 @@ vm_method_cfunc_entry(const rb_callable_method_entry_t *me)
return UNALIGNED_MEMBER_PTR(me->def, body.cfunc);
}
-/* -- Remove empty_kw_splat In 3.0 -- */
static VALUE
-vm_call_cfunc_with_frame(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, struct rb_call_data *cd, int empty_kw_splat)
+vm_call_cfunc_with_frame(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, struct rb_call_data *cd)
{
const struct rb_call_info *ci = &cd->ci;
const struct rb_call_cache *cc = &cd->cc;
@@ -2506,9 +2505,6 @@ vm_call_cfunc_with_frame(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp
if (UNLIKELY(calling->kw_splat)) {
frame_type |= VM_FRAME_FLAG_CFRAME_KW;
}
- else if (UNLIKELY(empty_kw_splat)) {
- frame_type |= VM_FRAME_FLAG_CFRAME_EMPTY_KW;
- }
RUBY_DTRACE_CMETHOD_ENTRY_HOOK(ec, me->owner, me->def->original_id);
EXEC_EVENT_HOOK(ec, RUBY_EVENT_C_CALL, recv, me->def->original_id, ci->mid, me->owner, Qundef);
@@ -2536,16 +2532,11 @@ static VALUE
vm_call_cfunc(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, struct rb_call_data *cd)
{
const struct rb_call_info *ci = &cd->ci;
- int empty_kw_splat;
RB_DEBUG_COUNTER_INC(ccf_cfunc);
CALLER_SETUP_ARG(reg_cfp, calling, ci);
- empty_kw_splat = calling->kw_splat;
CALLER_REMOVE_EMPTY_KW_SPLAT(reg_cfp, calling, ci);
- if (empty_kw_splat && calling->kw_splat) {
- empty_kw_splat = 0;
- }
- return vm_call_cfunc_with_frame(ec, reg_cfp, calling, cd, empty_kw_splat);
+ return vm_call_cfunc_with_frame(ec, reg_cfp, calling, cd);
}
static VALUE
@@ -2935,12 +2926,7 @@ vm_call_method_each_type(rb_execution_context_t *ec, rb_control_frame_t *cfp, st
case VM_METHOD_TYPE_ATTRSET:
CALLER_SETUP_ARG(cfp, calling, ci);
- if (calling->argc == 1 && calling->kw_splat && RHASH_EMPTY_P(cfp->sp[-1])) {
- rb_warn_keyword_to_last_hash(ec, calling, ci, NULL);
- }
- else {
- CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling, ci);
- }
+ CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling, ci);
rb_check_arity(calling->argc, 1, 1);
cc->aux.index = 0;
@@ -3211,13 +3197,8 @@ vm_yield_with_cfunc(rb_execution_context_t *ec,
blockarg = rb_vm_bh_to_procval(ec, block_handler);
frame_flag = VM_FRAME_MAGIC_IFUNC | VM_FRAME_FLAG_CFRAME | (me ? VM_FRAME_FLAG_BMETHOD : 0);
- switch (kw_splat) {
- case 1:
- frame_flag |= VM_FRAME_FLAG_CFRAME_KW;
- break;
- case 2:
- frame_flag |= VM_FRAME_FLAG_CFRAME_EMPTY_KW;
- break;
+ if (kw_splat) {
+ frame_flag |= VM_FRAME_FLAG_CFRAME_KW;
}
vm_push_frame(ec, (const rb_iseq_t *)captured->code.ifunc,
@@ -3274,12 +3255,7 @@ vm_callee_setup_block_arg(rb_execution_context_t *ec, struct rb_calling_info *ca
VALUE arg0;
CALLER_SETUP_ARG(cfp, calling, ci);
- if (calling->kw_splat && calling->argc == iseq->body->param.lead_num + iseq->body->param.post_num && RHASH_EMPTY_P(cfp->sp[-1])) {
- rb_warn_keyword_to_last_hash(ec, calling, ci, iseq);
- }
- else {
- CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling, ci);
- }
+ CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling, ci);
if (arg_setup_type == arg_setup_block &&
calling->argc == 1 &&
@@ -3377,17 +3353,10 @@ vm_invoke_ifunc_block(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
{
VALUE val;
int argc;
- int kw_splat = calling->kw_splat;
CALLER_SETUP_ARG(ec->cfp, calling, ci);
CALLER_REMOVE_EMPTY_KW_SPLAT(ec->cfp, calling, ci);
- if (kw_splat && !calling->kw_splat) {
- kw_splat = 2;
- }
- else {
- kw_splat = calling->kw_splat;
- }
argc = calling->argc;
- val = vm_yield_with_cfunc(ec, captured, captured->self, argc, STACK_ADDR_FROM_TOP(argc), kw_splat, calling->block_handler, NULL);
+ val = vm_yield_with_cfunc(ec, captured, captured->self, argc, STACK_ADDR_FROM_TOP(argc), calling->kw_splat, calling->block_handler, NULL);
POPN(argc); /* TODO: should put before C/yield? */
return val;
}