diff --git a/lib/parser/builders/default.rb b/lib/parser/builders/default.rb index dce8044eb..b55f76381 100644 --- a/lib/parser/builders/default.rb +++ b/lib/parser/builders/default.rb @@ -743,14 +743,18 @@ def numargs(max_numparam) def forward_only_args(begin_t, dots_t, end_t) if self.class.emit_forward_arg - forward_arg = n(:forward_arg, [], token_map(dots_t)) - n(:args, [ forward_arg ], - collection_map(begin_t, [ forward_arg ], end_t)) + arg = forward_arg(dots_t) + n(:args, [ arg ], + collection_map(begin_t, [ arg ], end_t)) else n(:forward_args, [], collection_map(begin_t, token_map(dots_t), end_t)) end end + def forward_arg(dots_t) + n(:forward_arg, [], token_map(dots_t)) + end + def arg(name_t) n(:arg, [ value(name_t).to_sym ], variable_map(name_t)) diff --git a/lib/parser/ruby28.y b/lib/parser/ruby28.y index 3da698cdb..ea44fd09e 100644 --- a/lib/parser/ruby28.y +++ b/lib/parser/ruby28.y @@ -960,6 +960,14 @@ rule { result = val } + | tLPAREN2 args tCOMMA args_forward rparen + { + unless @static_env.declared_forward_args? + diagnostic :error, :unexpected_token, { :token => 'tBDOT3' } , val[3] + end + + result = [val[0], [*val[1], @builder.forwarded_args(val[3])], val[4]] + } | tLPAREN2 args_forward rparen { unless @static_env.declared_forward_args? @@ -2593,6 +2601,13 @@ keyword_variable: kNIL @lexer.state = :expr_value } + | tLPAREN2 f_arg tCOMMA args_forward rparen + { + args = [ *val[1], @builder.forward_arg(val[3]) ] + result = @builder.args(val[0], args, val[4]) + + @static_env.declare_forward_args + } | tLPAREN2 args_forward rparen { result = @builder.forward_only_args(val[0], val[1], val[2]) diff --git a/test/test_parser.rb b/test/test_parser.rb index 825793799..e63e17eee 100644 --- a/test/test_parser.rb +++ b/test/test_parser.rb @@ -7890,6 +7890,12 @@ def test_forward_args_invalid %q{ ^^^ location}, SINCE_2_7) + assert_diagnoses( + [:error, :unexpected_token, { :token => 'tBDOT3' }], + %q{def foo(x,y,z); bar(x, y, z, ...); end}, + %q{ ^^^ location}, + SINCE_2_8) + assert_diagnoses( [:error, :unexpected_token, { :token => 'tBDOT3' }], %q{def foo(x,y,z); super(...); end}, @@ -7959,6 +7965,26 @@ def test_forward_args_invalid SINCE_2_7) end + def test_trailing_forward_arg + assert_parses( + s(:def, :foo, + s(:args, + s(:arg, :a), + s(:arg, :b), + s(:forward_arg)), + s(:send, nil, :bar, + s(:lvar, :a), + s(:int, 42), + s(:forwarded_args))), + %q{def foo(a, b, ...); bar(a, 42, ...); end}, + %q{ ~ begin (args) + | ~~~~~~~~~~~ expression (args) + | ~ end (args) + | ~~~ expression (args.forward_arg)}, + SINCE_2_8) + end + + def test_erange_without_parentheses_at_eol assert_diagnoses( [:warning, :triple_dot_at_eol],