mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Implement keyword argument to last positional hash emulation
For methods that accept keyword arguments but do not accept a keyword splat, if a keyword splat is passed, or keywords are used with a non-symbol key, check the hash. If the hash contains all symbols, keep the same behavior as before. If the hash contains all non-symbols, move the hash to the last positional hash and warn. If the hash contains symbols and non-Symbols, split the hash and use the symbol keys for the keyword hash and non-symbol keys for the positional hash and warn.
This commit is contained in:
parent
8399609e5a
commit
5c507db467
Notes:
git
2019-08-31 04:40:14 +09:00
1 changed files with 27 additions and 1 deletions
28
vm_args.c
28
vm_args.c
|
@ -584,6 +584,20 @@ get_loc(struct rb_calling_info *calling, const struct rb_call_info *ci)
|
||||||
return rb_obj_method_location(calling->recv, ci->mid);
|
return rb_obj_method_location(calling->recv, ci->mid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 passed as the last hash parameter", rb_id2name(ci->mid));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rb_warn("The keyword argument for `%s' (defined at %s:%d) is passed as the last hash parameter",
|
||||||
|
rb_id2name(ci->mid), RSTRING_PTR(RARRAY_AREF(loc, 0)), FIX2INT(RARRAY_AREF(loc, 1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
rb_warn_split_last_hash_to_keyword(struct rb_calling_info *calling, const struct rb_call_info *ci)
|
rb_warn_split_last_hash_to_keyword(struct rb_calling_info *calling, const struct rb_call_info *ci)
|
||||||
{
|
{
|
||||||
|
@ -746,9 +760,21 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
|
||||||
(kw_splat && given_argc > max_argc)) &&
|
(kw_splat && given_argc > max_argc)) &&
|
||||||
args->kw_argv == NULL) {
|
args->kw_argv == NULL) {
|
||||||
if (((kw_flag & (VM_CALL_KWARG | VM_CALL_KW_SPLAT)) || !ec->cfp->iseq /* called from C */)) {
|
if (((kw_flag & (VM_CALL_KWARG | VM_CALL_KW_SPLAT)) || !ec->cfp->iseq /* called from C */)) {
|
||||||
if (args_pop_keyword_hash(args, &keyword_hash, 0)) {
|
int check_only_symbol = (kw_flag & VM_CALL_KW_SPLAT) &&
|
||||||
|
iseq->body->param.flags.has_kw &&
|
||||||
|
!iseq->body->param.flags.has_kwrest;
|
||||||
|
|
||||||
|
if (args_pop_keyword_hash(args, &keyword_hash, check_only_symbol)) {
|
||||||
given_argc--;
|
given_argc--;
|
||||||
}
|
}
|
||||||
|
else if (check_only_symbol) {
|
||||||
|
if (keyword_hash != Qnil) {
|
||||||
|
rb_warn_split_last_hash_to_keyword(calling, ci);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rb_warn_keyword_to_last_hash(calling, ci);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (args_pop_keyword_hash(args, &keyword_hash, 1)) {
|
else if (args_pop_keyword_hash(args, &keyword_hash, 1)) {
|
||||||
/* Warn the following:
|
/* Warn the following:
|
||||||
|
|
Loading…
Reference in a new issue