Project

General

Profile

Feature #14183 » vm_args.diff

jeremyevans0 (Jeremy Evans), 03/25/2019 10:48 PM

View differences:

vm_args.c
return ST_CONTINUE;
}
static inline int
ignore_keyword_hash_p(VALUE keyword_hash, const rb_iseq_t * const iseq) {
if (keyword_hash == rb_no_keyword_hash) {
return 1;
} else if (!(iseq->body->param.flags.has_kw) &&
!(iseq->body->param.flags.has_kwrest)) {
keyword_hash = rb_check_hash_type(keyword_hash);
if (!NIL_P(keyword_hash) && RHASH_EMPTY_P(keyword_hash)) {
return 1;
}
}
return 0;
}
static inline VALUE
get_loc(struct rb_calling_info *calling, const struct rb_call_info *ci)
{
......
}
}
static inline void
rb_warn_keyword_to_last_hash(struct rb_calling_info *calling, const struct rb_call_info *ci)
{
if (calling->recv == Qundef) return;
VALUE loc = get_loc(calling, ci);
if (NIL_P(loc)) {
rb_warn("The keyword argument for `%s' is used as the last parameter", rb_id2name(ci->mid));
}
else {
rb_warn("The keyword argument for `%s' (defined at %s:%d) is used as the last parameter",
rb_id2name(ci->mid), RSTRING_PTR(RARRAY_AREF(loc, 0)), FIX2INT(RARRAY_AREF(loc, 1)));
}
}
static int
setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * const iseq,
struct rb_calling_info *const calling,
......
VALUE keyword_hash = Qnil;
VALUE * const orig_sp = ec->cfp->sp;
unsigned int i;
int k2n_warned = FALSE;
vm_check_canary(ec, orig_sp);
/*
......
given_argc += RARRAY_LENINT(args->rest) - 1;
if (kw_flag & VM_CALL_KW_SPLAT) {
int len = RARRAY_LENINT(args->rest);
if (len > 0 && RARRAY_AREF(args->rest, len - 1) == rb_no_keyword_hash) {
if (len > 0 && ignore_keyword_hash_p(RARRAY_AREF(args->rest, len - 1), iseq)) {
arg_rest_dup(args);
rb_ary_pop(args->rest);
given_argc--;
kw_flag &= ~VM_CALL_KW_SPLAT;
}
}
}
}
else {
if (kw_flag & VM_CALL_KW_SPLAT) {
if (args->argv[args->argc-1] == rb_no_keyword_hash) {
if (ignore_keyword_hash_p(args->argv[args->argc-1], iseq)) {
args->argc--;
given_argc--;
kw_flag &= ~VM_CALL_KW_SPLAT;
}
}
}
args->rest = Qfalse;
}
......
/* argc check */
if (given_argc < min_argc) {
if (given_argc == min_argc - 1 && args->kw_argv) {
/* Warn the following:
* def foo(a, k:1) p [a, k] end
* foo(k:42) #=> [{:k=>42}, 1]
*/
rb_warn_keyword_to_last_hash(calling, ci);
k2n_warned = TRUE;
args_stored_kw_argv_to_hash(args);
given_argc = args_argc(args);
}
......
}
}
}
else if (!k2n_warned &&
!((kw_flag & VM_CALL_KWARG) && iseq->body->param.flags.has_kw) &&
given_argc == min_argc + 1 &&
(kw_flag & (VM_CALL_KWARG | VM_CALL_KW_SPLAT))) {
/* Warn the following:
* def foo(x, opt=1) p [x]; end
* foo(k:42) #=> [{:k=>42}]
*/
rb_warn_keyword_to_last_hash(calling, ci);
}
if (given_argc > max_argc && max_argc != UNLIMITED_ARGUMENTS) {
if (arg_setup_type == arg_setup_block) {
......
VALUE *sp = cfp->sp;
int i;
/* Warn the following:
* def foo(x) p [x] end
* foo(k:42) #=> [{:k=>42}]
*/
if (!cfunc) {
rb_warn_keyword_to_last_hash(calling, ci);
}
for (i=0; i<kw_len; i++) {
rb_hash_aset(h, passed_keywords[i], (sp - kw_len)[i]);
}
(1-1/2)