From a7b4ac293ee3721b6a19b497c3d6c1c36fed6e3e Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Fri, 20 Dec 2024 11:49:22 +0100 Subject: [PATCH 1/2] - builder.rb: emit `kwargs` node for `indexasgn` when opted in --- lib/parser/builders/default.rb | 4 ++++ test/test_parser.rb | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/lib/parser/builders/default.rb b/lib/parser/builders/default.rb index 115ef403b..29cf2e927 100644 --- a/lib/parser/builders/default.rb +++ b/lib/parser/builders/default.rb @@ -1192,6 +1192,10 @@ def index(receiver, lbrack_t, indexes, rbrack_t) end def index_asgn(receiver, lbrack_t, indexes, rbrack_t) + if self.class.emit_kwargs + rewrite_hash_args_to_kwargs(indexes) + end + if self.class.emit_index n(:indexasgn, [ receiver, *indexes ], index_map(receiver, lbrack_t, rbrack_t)) diff --git a/test/test_parser.rb b/test/test_parser.rb index d67c09873..1ed967a85 100644 --- a/test/test_parser.rb +++ b/test/test_parser.rb @@ -3625,6 +3625,33 @@ def test_send_index_asgn_legacy Parser::Builders::Default.emit_index = true end + def test_send_index_asgn_kwarg + assert_parses( + s(:indexasgn, + s(:lvar, :foo), + s(:kwargs, + s(:pair, + s(:sym, :kw), + s(:send, nil, :arg))), + s(:int, 3)), + %q{foo[:kw => arg] = 3}) + end + + def test_send_index_asgn_kwarg_legacy + Parser::Builders::Default.emit_kwargs = false + assert_parses( + s(:indexasgn, + s(:lvar, :foo), + s(:hash, + s(:pair, + s(:sym, :kw), + s(:send, nil, :arg))), + s(:int, 3)), + %q{foo[:kw => arg] = 3}) + ensure + Parser::Builders::Default.emit_kwargs = true + end + def test_send_lambda assert_parses( s(:block, s(:lambda), From 7f7a9aa9498214b5e75634e7ba8d8e80a27b83cb Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Sat, 21 Dec 2024 12:46:22 +0100 Subject: [PATCH 2/2] + builder.rb: disallow kwargs and blocks in index for Ruby 3.4 This tracks upstream commit https://github.com/ruby/ruby/commit/df5ef282337764508a1e1d93459d7a280e46647c and https://github.com/ruby/ruby/commit/0d5b16599a4ad606619228623299b931c48b597b --- lib/parser/builders/default.rb | 9 +++++++ lib/parser/messages.rb | 1 + test/test_parser.rb | 44 ++++++++++++++++++++++++++++++++-- 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/lib/parser/builders/default.rb b/lib/parser/builders/default.rb index 29cf2e927..defe6d947 100644 --- a/lib/parser/builders/default.rb +++ b/lib/parser/builders/default.rb @@ -1192,6 +1192,15 @@ def index(receiver, lbrack_t, indexes, rbrack_t) end def index_asgn(receiver, lbrack_t, indexes, rbrack_t) + if @parser.version >= 34 && (last = indexes.last) + if kwargs?(last) + diagnostic :error, :invalid_arg_in_index_assign, { :type => "keyword"}, last.loc.expression + end + if last.type == :block_pass + diagnostic :error, :invalid_arg_in_index_assign, { :type => "block"}, last.loc.expression + end + end + if self.class.emit_kwargs rewrite_hash_args_to_kwargs(indexes) end diff --git a/lib/parser/messages.rb b/lib/parser/messages.rb index c82c6343a..33ed19c14 100644 --- a/lib/parser/messages.rb +++ b/lib/parser/messages.rb @@ -85,6 +85,7 @@ module Parser :ambiguous_anonymous_restarg => 'anonymous rest parameter is also used within block', :ambiguous_anonymous_kwrestarg => 'anonymous keyword rest parameter is also used within block', :ambiguous_anonymous_blockarg => 'anonymous block parameter is also used within block', + :invalid_arg_in_index_assign => '%{type} argument given in index assignment', # Parser warnings :useless_else => 'else without rescue is useless', diff --git a/test/test_parser.rb b/test/test_parser.rb index 1ed967a85..49a794969 100644 --- a/test/test_parser.rb +++ b/test/test_parser.rb @@ -3634,7 +3634,9 @@ def test_send_index_asgn_kwarg s(:sym, :kw), s(:send, nil, :arg))), s(:int, 3)), - %q{foo[:kw => arg] = 3}) + %q{foo[:kw => arg] = 3}, + %q{}, + ALL_VERSIONS - SINCE_3_4) end def test_send_index_asgn_kwarg_legacy @@ -3647,11 +3649,49 @@ def test_send_index_asgn_kwarg_legacy s(:sym, :kw), s(:send, nil, :arg))), s(:int, 3)), - %q{foo[:kw => arg] = 3}) + %q{foo[:kw => arg] = 3}, + %q{}, + ALL_VERSIONS - SINCE_3_4) ensure Parser::Builders::Default.emit_kwargs = true end + def test_send_index_asgn_since_34 + [true, false].each do |emit_kwargs| + Parser::Builders::Default.emit_kwargs = emit_kwargs + + [ + %q{foo[:kw => arg] = 3}, + %q{foo[**args] = 3}, + %q{def x(**); foo[**] = 3; end}, + ].each do |code| + assert_diagnoses( + [:error, :invalid_arg_in_index_assign, { :type => "keyword" }], + code, + %q{}, + SINCE_3_4) + end + + refute_diagnoses( + %q{foo[{}]}, + ALL_VERSIONS) + + [ + %q{foo[&blk] = 3}, + %q{def x(&); foo[&] = 3; end}, + %q{foo[&method(:foo)] = 3}, + ].each do |code| + assert_diagnoses( + [:error, :invalid_arg_in_index_assign, { :type => "block" }], + code, + %q{}, + SINCE_3_4) + end + ensure + Parser::Builders::Default.emit_kwargs = true + end + end + def test_send_lambda assert_parses( s(:block, s(:lambda),