From c8d162c889008028b148437d02f36f4edaa749fd Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Thu, 26 Oct 2023 14:28:39 +0900 Subject: [PATCH] [Bug #19973] Warn duplicated keyword arguments after keyword splat --- parse.y | 11 +++++++---- test/ruby/test_syntax.rb | 6 ++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/parse.y b/parse.y index 46d9567093..eb2a2b3984 100644 --- a/parse.y +++ b/parse.y @@ -14551,15 +14551,18 @@ remove_duplicate_keys(struct parser_params *p, NODE *hash) NODE *result = 0; NODE *last_expr = 0; rb_code_location_t loc = hash->nd_loc; - while (hash && RNODE_LIST(hash)->nd_head && RNODE_LIST(hash)->nd_next) { + while (hash && RNODE_LIST(hash)->nd_next) { NODE *head = RNODE_LIST(hash)->nd_head; NODE *value = RNODE_LIST(hash)->nd_next; NODE *next = RNODE_LIST(value)->nd_next; st_data_t key = (st_data_t)head; st_data_t data; RNODE_LIST(value)->nd_next = 0; - if (nd_type_p(head, NODE_LIT) && - st_delete(literal_keys, (key = (st_data_t)RNODE_LIT(head)->nd_lit, &key), &data)) { + if (!head) { + key = (st_data_t)value; + } + else if (nd_type_p(head, NODE_LIT) && + st_delete(literal_keys, (key = (st_data_t)RNODE_LIT(head)->nd_lit, &key), &data)) { NODE *dup_value = (RNODE_LIST((NODE *)data))->nd_next; rb_compile_warn(p->ruby_sourcefile, nd_line((NODE *)data), "key %+"PRIsVALUE" is duplicated and overwritten on line %d", @@ -14572,7 +14575,7 @@ remove_duplicate_keys(struct parser_params *p, NODE *hash) } } st_insert(literal_keys, (st_data_t)key, (st_data_t)hash); - last_expr = nd_type_p(head, NODE_LIT) ? value : head; + last_expr = !head || nd_type_p(head, NODE_LIT) ? value : head; hash = next; } st_foreach(literal_keys, append_literal_keys, (st_data_t)&result); diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb index cda84c6368..69d1bb3024 100644 --- a/test/ruby/test_syntax.rb +++ b/test/ruby/test_syntax.rb @@ -335,6 +335,12 @@ class TestSyntax < Test::Unit::TestCase assert_warn(/duplicated/) {r = eval("a.f(**{k: a.add(1), j: a.add(2), k: a.add(3), k: a.add(4)})")} assert_equal(4, r) assert_equal([1, 2, 3, 4], a) + a.clear + r = nil + z = {} + assert_warn(/duplicated/) {r = eval("a.f(k: a.add(1), **z, k: a.add(2))")} + assert_equal(2, r) + assert_equal([1, 2], a) end def test_keyword_empty_splat