mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Allow ** syntax to be used for calling methods that do not accept keywords
Treat the ** syntax as passing a copy of the hash as the last positional argument. If the hash being double splatted is empty, do not add a positional argument. Remove rb_no_keyword_hash, no longer needed.
This commit is contained in:
parent
16c6984bb9
commit
334b41a46b
Notes:
git
2019-08-31 04:40:19 +09:00
4 changed files with 19 additions and 65 deletions
8
hash.c
8
hash.c
|
@ -30,8 +30,6 @@
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VALUE rb_no_keyword_hash;
|
|
||||||
|
|
||||||
#ifndef HASH_DEBUG
|
#ifndef HASH_DEBUG
|
||||||
#define HASH_DEBUG 0
|
#define HASH_DEBUG 0
|
||||||
#endif
|
#endif
|
||||||
|
@ -3276,8 +3274,6 @@ inspect_hash(VALUE hash, VALUE dummy, int recur)
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_hash_inspect(VALUE hash)
|
rb_hash_inspect(VALUE hash)
|
||||||
{
|
{
|
||||||
if (hash == rb_no_keyword_hash)
|
|
||||||
return rb_usascii_str_new2("{(NO KEYWORD)}");
|
|
||||||
if (RHASH_EMPTY_P(hash))
|
if (RHASH_EMPTY_P(hash))
|
||||||
return rb_usascii_str_new2("{}");
|
return rb_usascii_str_new2("{}");
|
||||||
return rb_exec_recursive(inspect_hash, hash, 0);
|
return rb_exec_recursive(inspect_hash, hash, 0);
|
||||||
|
@ -6277,10 +6273,6 @@ Init_Hash(void)
|
||||||
*/
|
*/
|
||||||
rb_define_global_const("ENV", envtbl);
|
rb_define_global_const("ENV", envtbl);
|
||||||
|
|
||||||
rb_no_keyword_hash = rb_hash_new();
|
|
||||||
rb_hash_freeze(rb_no_keyword_hash);
|
|
||||||
rb_gc_register_mark_object(rb_no_keyword_hash);
|
|
||||||
|
|
||||||
/* for callcc */
|
/* for callcc */
|
||||||
ruby_register_rollback_func_for_ensure(hash_foreach_ensure, hash_foreach_ensure_rollback);
|
ruby_register_rollback_func_for_ensure(hash_foreach_ensure, hash_foreach_ensure_rollback);
|
||||||
|
|
||||||
|
|
|
@ -2397,7 +2397,6 @@ VALUE rb_str_normalize_ospath(const char *ptr, long len);
|
||||||
/* hash.c (export) */
|
/* hash.c (export) */
|
||||||
VALUE rb_hash_delete_entry(VALUE hash, VALUE key);
|
VALUE rb_hash_delete_entry(VALUE hash, VALUE key);
|
||||||
VALUE rb_ident_hash_new(void);
|
VALUE rb_ident_hash_new(void);
|
||||||
extern VALUE rb_no_keyword_hash;
|
|
||||||
|
|
||||||
/* io.c (export) */
|
/* io.c (export) */
|
||||||
void rb_maygvl_fd_fix_cloexec(int fd);
|
void rb_maygvl_fd_fix_cloexec(int fd);
|
||||||
|
|
5
vm.c
5
vm.c
|
@ -2779,9 +2779,6 @@ static VALUE core_hash_merge_kwd(VALUE hash, VALUE kw);
|
||||||
static VALUE
|
static VALUE
|
||||||
core_hash_merge(VALUE hash, long argc, const VALUE *argv)
|
core_hash_merge(VALUE hash, long argc, const VALUE *argv)
|
||||||
{
|
{
|
||||||
if (hash == rb_no_keyword_hash) {
|
|
||||||
hash = rb_hash_new();
|
|
||||||
}
|
|
||||||
Check_Type(hash, T_HASH);
|
Check_Type(hash, T_HASH);
|
||||||
VM_ASSERT(argc % 2 == 0);
|
VM_ASSERT(argc % 2 == 0);
|
||||||
rb_hash_bulk_insert(argc, argv, hash);
|
rb_hash_bulk_insert(argc, argv, hash);
|
||||||
|
@ -2815,8 +2812,6 @@ m_core_hash_merge_kwd(VALUE recv, VALUE hash, VALUE kw)
|
||||||
static VALUE
|
static VALUE
|
||||||
core_hash_merge_kwd(VALUE hash, VALUE kw)
|
core_hash_merge_kwd(VALUE hash, VALUE kw)
|
||||||
{
|
{
|
||||||
if (RHASH_EMPTY_P(hash) && kw == rb_no_keyword_hash)
|
|
||||||
return rb_no_keyword_hash;
|
|
||||||
rb_hash_foreach(rb_to_hash_type(kw), kwmerge_i, hash);
|
rb_hash_foreach(rb_to_hash_type(kw), kwmerge_i, hash);
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
70
vm_args.c
70
vm_args.c
|
@ -186,11 +186,6 @@ args_rest_array(struct args_info *args)
|
||||||
static int
|
static int
|
||||||
keyword_hash_p(VALUE *kw_hash_ptr, VALUE *rest_hash_ptr)
|
keyword_hash_p(VALUE *kw_hash_ptr, VALUE *rest_hash_ptr)
|
||||||
{
|
{
|
||||||
if (*kw_hash_ptr == rb_no_keyword_hash) {
|
|
||||||
*kw_hash_ptr = Qnil;
|
|
||||||
*rest_hash_ptr = Qfalse;
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
*rest_hash_ptr = rb_check_hash_type(*kw_hash_ptr);
|
*rest_hash_ptr = rb_check_hash_type(*kw_hash_ptr);
|
||||||
|
|
||||||
if (!NIL_P(*rest_hash_ptr)) {
|
if (!NIL_P(*rest_hash_ptr)) {
|
||||||
|
@ -487,7 +482,7 @@ args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *cons
|
||||||
static inline void
|
static inline void
|
||||||
args_setup_kw_rest_parameter(VALUE keyword_hash, VALUE *locals)
|
args_setup_kw_rest_parameter(VALUE keyword_hash, VALUE *locals)
|
||||||
{
|
{
|
||||||
locals[0] = NIL_P(keyword_hash) ? rb_no_keyword_hash : rb_hash_dup(keyword_hash);
|
locals[0] = NIL_P(keyword_hash) ? rb_hash_new() : rb_hash_dup(keyword_hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
@ -513,6 +508,20 @@ fill_keys_values(st_data_t key, st_data_t val, st_data_t ptr)
|
||||||
return ST_CONTINUE;
|
return ST_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
ignore_keyword_hash_p(VALUE keyword_hash, const rb_iseq_t * const iseq) {
|
||||||
|
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
|
static inline VALUE
|
||||||
get_loc(struct rb_calling_info *calling, const struct rb_call_info *ci)
|
get_loc(struct rb_calling_info *calling, const struct rb_call_info *ci)
|
||||||
{
|
{
|
||||||
|
@ -533,20 +542,6 @@ rb_warn_last_hash_to_keyword(struct rb_calling_info *calling, const struct rb_ca
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
static int
|
||||||
setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * const iseq,
|
setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * const iseq,
|
||||||
struct rb_calling_info *const calling,
|
struct rb_calling_info *const calling,
|
||||||
|
@ -563,7 +558,6 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
|
||||||
VALUE keyword_hash = Qnil;
|
VALUE keyword_hash = Qnil;
|
||||||
VALUE * const orig_sp = ec->cfp->sp;
|
VALUE * const orig_sp = ec->cfp->sp;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int k2n_warned = FALSE;
|
|
||||||
|
|
||||||
vm_check_canary(ec, orig_sp);
|
vm_check_canary(ec, orig_sp);
|
||||||
/*
|
/*
|
||||||
|
@ -619,21 +613,21 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
|
||||||
given_argc += RARRAY_LENINT(args->rest) - 1;
|
given_argc += RARRAY_LENINT(args->rest) - 1;
|
||||||
if (kw_flag & VM_CALL_KW_SPLAT) {
|
if (kw_flag & VM_CALL_KW_SPLAT) {
|
||||||
int len = RARRAY_LENINT(args->rest);
|
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);
|
arg_rest_dup(args);
|
||||||
rb_ary_pop(args->rest);
|
rb_ary_pop(args->rest);
|
||||||
given_argc--;
|
given_argc--;
|
||||||
kw_flag &= ~VM_CALL_KW_SPLAT;
|
kw_flag &= ~VM_CALL_KW_SPLAT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (kw_flag & VM_CALL_KW_SPLAT) {
|
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--;
|
args->argc--;
|
||||||
given_argc--;
|
given_argc--;
|
||||||
kw_flag &= ~VM_CALL_KW_SPLAT;
|
kw_flag &= ~VM_CALL_KW_SPLAT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
args->rest = Qfalse;
|
args->rest = Qfalse;
|
||||||
}
|
}
|
||||||
|
@ -655,12 +649,6 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
|
||||||
/* argc check */
|
/* argc check */
|
||||||
if (given_argc < min_argc) {
|
if (given_argc < min_argc) {
|
||||||
if (given_argc == min_argc - 1 && args->kw_argv) {
|
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);
|
args_stored_kw_argv_to_hash(args);
|
||||||
given_argc = args_argc(args);
|
given_argc = args_argc(args);
|
||||||
}
|
}
|
||||||
|
@ -702,16 +690,6 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!k2n_warned &&
|
|
||||||
!((kw_flag & VM_CALL_KWARG) && iseq->body->param.flags.has_kw) &&
|
|
||||||
given_argc > min_argc &&
|
|
||||||
(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 (given_argc > max_argc && max_argc != UNLIMITED_ARGUMENTS) {
|
||||||
if (arg_setup_type == arg_setup_block) {
|
if (arg_setup_type == arg_setup_block) {
|
||||||
|
@ -880,8 +858,6 @@ vm_caller_setup_arg_splat(rb_control_frame_t *cfp, struct rb_calling_info *calli
|
||||||
|
|
||||||
CHECK_VM_STACK_OVERFLOW(cfp, len);
|
CHECK_VM_STACK_OVERFLOW(cfp, len);
|
||||||
|
|
||||||
if (ptr[len - 1] == rb_no_keyword_hash) len--;
|
|
||||||
|
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
*cfp->sp++ = ptr[i];
|
*cfp->sp++ = ptr[i];
|
||||||
}
|
}
|
||||||
|
@ -899,14 +875,6 @@ vm_caller_setup_arg_kw(rb_control_frame_t *cfp, struct rb_calling_info *calling,
|
||||||
VALUE *sp = cfp->sp;
|
VALUE *sp = cfp->sp;
|
||||||
int i;
|
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++) {
|
for (i=0; i<kw_len; i++) {
|
||||||
rb_hash_aset(h, passed_keywords[i], (sp - kw_len)[i]);
|
rb_hash_aset(h, passed_keywords[i], (sp - kw_len)[i]);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue