summaryrefslogtreecommitdiff
path: root/compile.c
diff options
context:
space:
mode:
authormame <mame@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2019-03-14 09:04:57 +0000
committermame <mame@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2019-03-14 09:04:57 +0000
commit3db2041f8772ec7c9faf379095d4c8d06e5e25ed (patch)
tree35adbc814efa5fc9a7ee34bfef6bbbc32c46e4ae /compile.c
parent146bb252a0fe114befe8aa762596563c886db7fc (diff)
compile.c: fix the corner case of rest and keyword arguments
See https://bugs.ruby-lang.org/issues/10856#note-20 . [Bug #10856] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@67256 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'compile.c')
-rw-r--r--compile.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/compile.c b/compile.c
index da23ac83c0..7201447d97 100644
--- a/compile.c
+++ b/compile.c
@@ -4773,6 +4773,22 @@ add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
ADD_SEQ(ret, ensure);
}
+static int
+check_keyword(const NODE *node)
+{
+ /* This check is essentially a code clone of compile_keyword_arg. */
+
+ if (nd_type(node) == NODE_ARRAY) {
+ while (node->nd_next) {
+ node = node->nd_next;
+ }
+ node = node->nd_head;
+ }
+
+ if (nd_type(node) == NODE_HASH && !node->nd_alen) return TRUE;
+ return FALSE;
+}
+
static VALUE
setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
int dup_rest, unsigned int *flag, struct rb_call_info_kw_arg **keywords)
@@ -4792,8 +4808,9 @@ setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
COMPILE(args, "args (cat: splat)", argn->nd_body);
if (flag) {
*flag |= VM_CALL_ARGS_SPLAT;
- if (nd_type(argn->nd_body) == NODE_HASH)
- /* bug: https://bugs.ruby-lang.org/issues/10856#change-77095 */
+ /* This is a dirty hack. It traverses the AST twice.
+ * In a long term, it should be fixed by a redesign of keyword arguments */
+ if (check_keyword(argn->nd_body))
*flag |= VM_CALL_KW_SPLAT;
}
if (nd_type(argn) == NODE_ARGSCAT) {