[前][次][番号順一覧][スレッド一覧]

ruby-changes:57408

From: Yusuke <ko1@a...>
Date: Sat, 31 Aug 2019 04:40:03 +0900 (JST)
Subject: [ruby-changes:57408] Yusuke Endoh: 16c6984bb9 (master): Separate keyword arguments from positional arguments

https://git.ruby-lang.org/ruby.git/commit/?id=16c6984bb9

From 16c6984bb97409029e213154ac4f633ae04af3d8 Mon Sep 17 00:00:00 2001
From: Yusuke Endoh <mame@r...>
Date: Mon, 18 Mar 2019 14:25:47 +0900
Subject: Separate keyword arguments from positional arguments

And, allow non-symbol keys as a keyword arugment

diff --git a/class.c b/class.c
index 2e87101..6b3b662 100644
--- a/class.c
+++ b/class.c
@@ -1830,8 +1830,7 @@ rb_keyword_error_new(const char *error, VALUE keys) https://github.com/ruby/ruby/blob/trunk/class.c#L1830
 	rb_str_cat_cstr(error_message, ": ");
 	while (1) {
             const VALUE k = RARRAY_AREF(keys, i);
-	    Check_Type(k, T_SYMBOL); /* wrong hash is given to rb_get_kwargs */
-	    rb_str_append(error_message, rb_sym2str(k));
+	    rb_str_append(error_message, rb_inspect(k));
 	    if (++i >= len) break;
 	    rb_str_cat_cstr(error_message, ", ");
 	}
diff --git a/compile.c b/compile.c
index cf29da3..63b893d 100644
--- a/compile.c
+++ b/compile.c
@@ -3798,7 +3798,7 @@ compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, https://github.com/ruby/ruby/blob/trunk/compile.c#L3798
 {
     if (kw_arg_ptr == NULL) return FALSE;
 
-    if (nd_type(root_node) == NODE_HASH && root_node->nd_head && nd_type(root_node->nd_head) == NODE_ARRAY) {
+    if (nd_type(root_node) == NODE_HASH && !root_node->nd_brace && root_node->nd_head && nd_type(root_node->nd_head) == NODE_ARRAY) {
 	const NODE *node = root_node->nd_head;
 
 	while (node) {
@@ -3806,13 +3806,14 @@ compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, https://github.com/ruby/ruby/blob/trunk/compile.c#L3806
 
 	    assert(nd_type(node) == NODE_ARRAY);
 	    if (!key_node) {
-                if (flag && !root_node->nd_brace) *flag |= VM_CALL_KW_SPLAT;
+		if (flag) *flag |= VM_CALL_KW_SPLAT;
 		return FALSE;
 	    }
 	    else if (nd_type(key_node) == NODE_LIT && RB_TYPE_P(key_node->nd_lit, T_SYMBOL)) {
 		/* can be keywords */
 	    }
 	    else {
+		if (flag) *flag |= VM_CALL_KW_SPLAT;
 		return FALSE;
 	    }
 	    node = node->nd_next; /* skip value node */
@@ -7351,6 +7352,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in https://github.com/ruby/ruby/blob/trunk/compile.c#L7352
 		    ADD_INSN (args, line, concatarray);
 		    --argc;
 		}
+		flag |= VM_CALL_KW_SPLAT;
 	    }
 	    else if (local_body->param.flags.has_kwrest) {
 		int idx = local_body->local_table_size - local_kwd->rest_start;
@@ -7364,6 +7366,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in https://github.com/ruby/ruby/blob/trunk/compile.c#L7366
 		else {
 		    argc++;
 		}
+		flag |= VM_CALL_KW_SPLAT;
 	    }
 	}
 
diff --git a/hash.c b/hash.c
index b61784a..0f1c460 100644
--- a/hash.c
+++ b/hash.c
@@ -30,6 +30,8 @@ https://github.com/ruby/ruby/blob/trunk/hash.c#L30
 # endif
 #endif
 
+VALUE rb_no_keyword_hash;
+
 #ifndef HASH_DEBUG
 #define HASH_DEBUG 0
 #endif
@@ -3274,6 +3276,8 @@ inspect_hash(VALUE hash, VALUE dummy, int recur) https://github.com/ruby/ruby/blob/trunk/hash.c#L3276
 static VALUE
 rb_hash_inspect(VALUE hash)
 {
+    if (hash == rb_no_keyword_hash)
+	return rb_usascii_str_new2("{(NO KEYWORD)}");
     if (RHASH_EMPTY_P(hash))
 	return rb_usascii_str_new2("{}");
     return rb_exec_recursive(inspect_hash, hash, 0);
@@ -6273,6 +6277,10 @@ Init_Hash(void) https://github.com/ruby/ruby/blob/trunk/hash.c#L6277
      */
     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 */
     ruby_register_rollback_func_for_ensure(hash_foreach_ensure, hash_foreach_ensure_rollback);
 
diff --git a/internal.h b/internal.h
index 5a846c1..2818467 100644
--- a/internal.h
+++ b/internal.h
@@ -2397,6 +2397,7 @@ VALUE rb_str_normalize_ospath(const char *ptr, long len); https://github.com/ruby/ruby/blob/trunk/internal.h#L2397
 /* hash.c (export) */
 VALUE rb_hash_delete_entry(VALUE hash, VALUE key);
 VALUE rb_ident_hash_new(void);
+extern VALUE rb_no_keyword_hash;
 
 /* io.c (export) */
 void rb_maygvl_fd_fix_cloexec(int fd);
diff --git a/parse.y b/parse.y
index 3c4a9d8..4dfdd5d 100644
--- a/parse.y
+++ b/parse.y
@@ -5134,12 +5134,6 @@ assocs		: assoc https://github.com/ruby/ruby/blob/trunk/parse.y#L5134
 			    assocs = tail;
 			}
 			else if (tail) {
-			    if (assocs->nd_head &&
-				!tail->nd_head && nd_type(tail->nd_next) == NODE_ARRAY &&
-				nd_type(tail->nd_next->nd_head) == NODE_HASH) {
-				/* DSTAR */
-				tail = tail->nd_next->nd_head->nd_head;
-			    }
 			    assocs = list_concat(assocs, tail);
 			}
 			$$ = assocs;
@@ -5177,11 +5171,7 @@ assoc		: arg_value tASSOC arg_value https://github.com/ruby/ruby/blob/trunk/parse.y#L5171
 		| tDSTAR arg_value
 		    {
 		    /*%%%*/
-			if (nd_type($2) == NODE_HASH &&
-			    !($2->nd_head && $2->nd_head->nd_alen))
-			    $$ = 0;
-			else
-			    $$ = list_append(p, NEW_LIST(0, &@$), $2);
+			$$ = list_append(p, NEW_LIST(0, &@$), $2);
 		    /*% %*/
 		    /*% ripper: assoc_splat!($2) %*/
 		    }
diff --git a/proc.c b/proc.c
index dd2fcfd..8f51ff1 100644
--- a/proc.c
+++ b/proc.c
@@ -2683,7 +2683,7 @@ rb_mod_method_location(VALUE mod, ID id) https://github.com/ruby/ruby/blob/trunk/proc.c#L2683
     return rb_method_entry_location(me);
 }
 
-VALUE
+MJIT_FUNC_EXPORTED VALUE
 rb_obj_method_location(VALUE obj, ID id)
 {
     return rb_mod_method_location(CLASS_OF(obj), id);
diff --git a/vm.c b/vm.c
index 157a439..c727554 100644
--- a/vm.c
+++ b/vm.c
@@ -2779,6 +2779,9 @@ static VALUE core_hash_merge_kwd(VALUE hash, VALUE kw); https://github.com/ruby/ruby/blob/trunk/vm.c#L2779
 static VALUE
 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);
     VM_ASSERT(argc % 2 == 0);
     rb_hash_bulk_insert(argc, argv, hash);
@@ -2790,23 +2793,14 @@ m_core_hash_merge_ptr(int argc, VALUE *argv, VALUE recv) https://github.com/ruby/ruby/blob/trunk/vm.c#L2793
 {
     VALUE hash = argv[0];
 
-    REWIND_CFP(core_hash_merge(hash, argc-1, argv+1));
+    REWIND_CFP(hash = core_hash_merge(hash, argc-1, argv+1));
 
     return hash;
 }
 
-static void
-kw_check_symbol(VALUE key)
-{
-    if (!SYMBOL_P(key)) {
-	rb_raise(rb_eTypeError, "hash key %+"PRIsVALUE" is not a Symbol",
-		 key);
-    }
-}
 static int
 kwmerge_i(VALUE key, VALUE value, VALUE hash)
 {
-    kw_check_symbol(key);
     rb_hash_aset(hash, key, value);
     return ST_CONTINUE;
 }
@@ -2821,6 +2815,8 @@ m_core_hash_merge_kwd(VALUE recv, VALUE hash, VALUE kw) https://github.com/ruby/ruby/blob/trunk/vm.c#L2815
 static VALUE
 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);
     return hash;
 }
diff --git a/vm_args.c b/vm_args.c
index 96fca84..42f6cff 100644
--- a/vm_args.c
+++ b/vm_args.c
@@ -186,12 +186,16 @@ args_rest_array(struct args_info *args) https://github.com/ruby/ruby/blob/trunk/vm_args.c#L186
 static int
 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);
 
     if (!NIL_P(*rest_hash_ptr)) {
-	VALUE hash = rb_extract_keywords(rest_hash_ptr);
-	if (!hash) hash = Qnil;
-	*kw_hash_ptr = hash;
+	*kw_hash_ptr = *rest_hash_ptr;
+	*rest_hash_ptr = Qfalse;
 	return TRUE;
     }
     else {
@@ -483,7 +487,7 @@ args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *cons https://github.com/ruby/ruby/blob/trunk/vm_args.c#L487
 static inline void
 args_setup_kw_rest_parameter(VALUE keyword_hash, VALUE *locals)
 {
-    locals[0] = NIL_P(keyword_hash) ? rb_hash_new() : rb_hash_dup(keyword_hash);
+    locals[0] = NIL_P(keyword_hash) ? rb_no_keyword_hash : rb_hash_dup(keyword_hash);
 }
 
 static inline void
@@ -509,6 +513,40 @@ fill_keys_values(st_data_t key, st_data_t val, st_data_t ptr) https://github.com/ruby/ruby/blob/trunk/vm_args.c#L513
     return ST_CONTINUE;
 }
 
+static inline VALUE
+get_loc(struct rb_calling_info *calling, const struct rb_call_info *ci)
+{
+    return rb_obj_method_location(calling->recv, ci->mid);
+}
+
+static inline void
+rb_warn_last_hash_to_keyword(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 last argument for `%s' is used as the keyword parameter", rb_id2name(ci->mid));
+    }
+    else {
+        rb_warn("The last argument for `%s' (defined at %s:%d) is used as the keyword parameter",
+                rb_id2name(ci->mid), RSTRING_PTR(RARRAY_AREF(loc, 0)), FIX2INT(RARRAY_AREF(loc, 1)));
+    }
+}
+
+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,
@@ -520,10 +558,12 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co https://github.com/ruby/ruby/blob/trunk/vm_args.c#L558
     int opt_pc = 0;
     int given_argc;
     int kw_splat = FALSE;
+    unsigned int kw_flag = ci->flag & (VM_CALL_KWARG | VM_CALL_KW_SPLAT);
     struct args_info args_body, *args;
     VALUE keyword_hash = Qnil;
     VALUE * const orig_sp = (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]