mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
splat keyword hash
* compile.c (compile_array_keyword_arg): set keyword splat flag if explicitly splatted. [ruby-core:68124] [Bug #10856] * vm_args.c (setup_parameters_complex): try keyword hash splat if given. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59519 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
d11dfab569
commit
26aed9c577
5 changed files with 32 additions and 10 deletions
21
compile.c
21
compile.c
|
@ -1088,7 +1088,7 @@ new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_cal
|
|||
iseq->body->ci_size++;
|
||||
}
|
||||
|
||||
if (!(ci->flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG)) &&
|
||||
if (!(ci->flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KW_SPLAT)) &&
|
||||
kw_arg == NULL && !has_blockiseq) {
|
||||
ci->flag |= VM_CALL_ARGS_SIMPLE;
|
||||
}
|
||||
|
@ -3040,7 +3040,8 @@ compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *const ret, NODE *cond,
|
|||
static int
|
||||
compile_array_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
|
||||
const NODE *const root_node,
|
||||
struct rb_call_info_kw_arg **const kw_arg_ptr)
|
||||
struct rb_call_info_kw_arg **const kw_arg_ptr,
|
||||
unsigned int *flag)
|
||||
{
|
||||
if (kw_arg_ptr == NULL) return FALSE;
|
||||
|
||||
|
@ -3055,6 +3056,7 @@ compile_array_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
|
|||
/* can be keywords */
|
||||
}
|
||||
else {
|
||||
if (flag) *flag |= VM_CALL_KW_SPLAT;
|
||||
return FALSE;
|
||||
}
|
||||
node = node->nd_next; /* skip value node */
|
||||
|
@ -3124,7 +3126,8 @@ static_literal_value(NODE *node)
|
|||
|
||||
static int
|
||||
compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, NODE* node_root,
|
||||
enum compile_array_type_t type, struct rb_call_info_kw_arg **keywords_ptr, int popped)
|
||||
enum compile_array_type_t type, struct rb_call_info_kw_arg **keywords_ptr,
|
||||
unsigned int *flag, int popped)
|
||||
{
|
||||
NODE *node = node_root;
|
||||
int line = (int)nd_line(node);
|
||||
|
@ -3169,7 +3172,9 @@ compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, NODE* node_root,
|
|||
opt_p = 0;
|
||||
}
|
||||
|
||||
if (type == COMPILE_ARRAY_TYPE_ARGS && node->nd_next == NULL /* last node */ && compile_array_keyword_arg(iseq, anchor, node->nd_head, keywords_ptr)) {
|
||||
if (type == COMPILE_ARRAY_TYPE_ARGS &&
|
||||
node->nd_next == NULL /* last node */ &&
|
||||
compile_array_keyword_arg(iseq, anchor, node->nd_head, keywords_ptr, flag)) {
|
||||
len--;
|
||||
}
|
||||
else {
|
||||
|
@ -3981,7 +3986,7 @@ setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, NODE *argn,
|
|||
*flag |= VM_CALL_ARGS_SPLAT;
|
||||
|
||||
if (next_is_array) {
|
||||
int len = compile_array(iseq, args, argn->nd_head, COMPILE_ARRAY_TYPE_ARGS, NULL, FALSE);
|
||||
int len = compile_array(iseq, args, argn->nd_head, COMPILE_ARRAY_TYPE_ARGS, NULL, flag, FALSE);
|
||||
if (len < 0) return Qnil;
|
||||
argc = INT2FIX(len + 1);
|
||||
}
|
||||
|
@ -3993,7 +3998,7 @@ setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, NODE *argn,
|
|||
}
|
||||
case NODE_ARRAY:
|
||||
{
|
||||
int len = compile_array(iseq, args, argn, COMPILE_ARRAY_TYPE_ARGS, keywords, FALSE);
|
||||
int len = compile_array(iseq, args, argn, COMPILE_ARRAY_TYPE_ARGS, keywords, flag, FALSE);
|
||||
if (len < 0) return Qnil;
|
||||
argc = INT2FIX(len);
|
||||
break;
|
||||
|
@ -5620,7 +5625,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, NODE *node, int popp
|
|||
break;
|
||||
}
|
||||
case NODE_ARRAY:{
|
||||
CHECK(compile_array(iseq, ret, node, COMPILE_ARRAY_TYPE_ARRAY, NULL, popped) >= 0);
|
||||
CHECK(compile_array(iseq, ret, node, COMPILE_ARRAY_TYPE_ARRAY, NULL, NULL, popped) >= 0);
|
||||
break;
|
||||
}
|
||||
case NODE_ZARRAY:{
|
||||
|
@ -5648,7 +5653,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, NODE *node, int popp
|
|||
INIT_ANCHOR(list);
|
||||
switch (type) {
|
||||
case NODE_ARRAY:
|
||||
CHECK(compile_array(iseq, list, node->nd_head, COMPILE_ARRAY_TYPE_HASH, NULL, popped) >= 0);
|
||||
CHECK(compile_array(iseq, list, node->nd_head, COMPILE_ARRAY_TYPE_HASH, NULL, NULL, popped) >= 0);
|
||||
ADD_SEQ(ret, list);
|
||||
break;
|
||||
|
||||
|
|
|
@ -503,6 +503,17 @@ class TestKeywordArguments < Test::Unit::TestCase
|
|||
assert_equal([1, 9], m1(1, o, &->(a, k: 0) {break [a, k]}), bug10016)
|
||||
end
|
||||
|
||||
def test_splat_hash
|
||||
m = Object.new
|
||||
def m.f() :ok; end
|
||||
o = {a: 1}
|
||||
assert_raise_with_message(ArgumentError, /unknown keyword: a/) {
|
||||
m.f(**o)
|
||||
}
|
||||
o = {}
|
||||
assert_equal(:ok, m.f(**o), '[ruby-core:68124] [Bug #10856]')
|
||||
end
|
||||
|
||||
def test_gced_object_in_stack
|
||||
bug8964 = '[ruby-dev:47729] [Bug #8964]'
|
||||
assert_normal_exit %q{
|
||||
|
|
|
@ -615,7 +615,8 @@ setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq,
|
|||
}
|
||||
|
||||
if (given_argc > min_argc &&
|
||||
(iseq->body->param.flags.has_kw || iseq->body->param.flags.has_kwrest) &&
|
||||
(iseq->body->param.flags.has_kw || iseq->body->param.flags.has_kwrest ||
|
||||
(!iseq->body->param.flags.has_rest && (ci->flag & VM_CALL_KW_SPLAT))) &&
|
||||
args->kw_argv == NULL) {
|
||||
if (args_pop_keyword_hash(args, &keyword_hash, th)) {
|
||||
given_argc--;
|
||||
|
@ -676,6 +677,9 @@ setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq,
|
|||
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(th, iseq, "unknown", rb_hash_keys(keyword_hash));
|
||||
}
|
||||
|
||||
if (iseq->body->param.flags.has_block) {
|
||||
args_setup_block_parameter(th, calling, locals + iseq->body->param.block_start);
|
||||
|
|
|
@ -949,6 +949,7 @@ enum vm_call_flag_bits {
|
|||
VM_CALL_ARGS_SIMPLE_bit, /* (ci->flag & (SPLAT|BLOCKARG)) && blockiseq == NULL && ci->kw_arg == NULL */
|
||||
VM_CALL_BLOCKISEQ_bit, /* has blockiseq */
|
||||
VM_CALL_KWARG_bit, /* has kwarg */
|
||||
VM_CALL_KW_SPLAT_bit, /* m(**opts) */
|
||||
VM_CALL_TAILCALL_bit, /* located at tail position */
|
||||
VM_CALL_SUPER_bit, /* super */
|
||||
VM_CALL_OPT_SEND_bit, /* internal flag */
|
||||
|
@ -962,6 +963,7 @@ enum vm_call_flag_bits {
|
|||
#define VM_CALL_ARGS_SIMPLE (0x01 << VM_CALL_ARGS_SIMPLE_bit)
|
||||
#define VM_CALL_BLOCKISEQ (0x01 << VM_CALL_BLOCKISEQ_bit)
|
||||
#define VM_CALL_KWARG (0x01 << VM_CALL_KWARG_bit)
|
||||
#define VM_CALL_KW_SPLAT (0x01 << VM_CALL_KW_SPLAT_bit)
|
||||
#define VM_CALL_TAILCALL (0x01 << VM_CALL_TAILCALL_bit)
|
||||
#define VM_CALL_SUPER (0x01 << VM_CALL_SUPER_bit)
|
||||
#define VM_CALL_OPT_SEND (0x01 << VM_CALL_OPT_SEND_bit)
|
||||
|
|
|
@ -1585,7 +1585,7 @@ static inline int
|
|||
vm_callee_setup_arg(rb_thread_t *th, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc,
|
||||
const rb_iseq_t *iseq, VALUE *argv, int param_size, int local_size)
|
||||
{
|
||||
if (LIKELY(simple_iseq_p(iseq))) {
|
||||
if (LIKELY(simple_iseq_p(iseq) && !(ci->flag & VM_CALL_KW_SPLAT))) {
|
||||
rb_control_frame_t *cfp = th->ec.cfp;
|
||||
|
||||
CALLER_SETUP_ARG(cfp, calling, ci); /* splat arg */
|
||||
|
|
Loading…
Add table
Reference in a new issue