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

ruby-changes:70213

From: Nobuyoshi <ko1@a...>
Date: Wed, 15 Dec 2021 07:01:40 +0900 (JST)
Subject: [ruby-changes:70213] aa7c4c37d7 (master): Fix arg_forward without parentheses [Bug #18267]

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

From aa7c4c37d7752af4897567dec1b0745873b0457a Mon Sep 17 00:00:00 2001
From: Nobuyoshi Nakada <nobu@r...>
Date: Thu, 18 Nov 2021 21:41:46 +0900
Subject: Fix arg_forward without parentheses [Bug #18267]

---
 parse.y                  | 40 +++++++++++++++++++++++++++++++---------
 test/ruby/test_syntax.rb | 25 ++++++++++++++++++++++++-
 2 files changed, 55 insertions(+), 10 deletions(-)

diff --git a/parse.y b/parse.y
index 31067947a93..0bf7b9c9aff 100644
--- a/parse.y
+++ b/parse.y
@@ -64,6 +64,7 @@ enum shareability { https://github.com/ruby/ruby/blob/trunk/parse.y#L64
 struct lex_context {
     unsigned int in_defined: 1;
     unsigned int in_kwarg: 1;
+    unsigned int in_argdef: 1;
     unsigned int in_def: 1;
     unsigned int in_class: 1;
     BITFIELD(enum shareability, shareable_constant_value, 2);
@@ -1817,7 +1818,12 @@ defn_head	: k_def def_name https://github.com/ruby/ruby/blob/trunk/parse.y#L1818
 		    }
 		;
 
-defs_head	: k_def singleton dot_or_colon {SET_LEX_STATE(EXPR_FNAME);} def_name
+defs_head	: k_def singleton dot_or_colon
+		    {
+			SET_LEX_STATE(EXPR_FNAME);
+			p->ctxt.in_argdef = 1;
+		    }
+		  def_name
 		    {
 			SET_LEX_STATE(EXPR_ENDFN|EXPR_LABEL); /* force for args */
 			$$ = $5;
@@ -3396,6 +3402,7 @@ k_module	: keyword_module https://github.com/ruby/ruby/blob/trunk/parse.y#L3402
 k_def		: keyword_def
 		    {
 			token_info_push(p, "def", &@$);
+			p->ctxt.in_argdef = 1;
 		    }
 		;
 
@@ -3591,6 +3598,8 @@ f_any_kwrest	: f_kwrest https://github.com/ruby/ruby/blob/trunk/parse.y#L3598
 		| f_no_kwarg {$$ = ID2VAL(idNil);}
 		;
 
+f_eq		: {p->ctxt.in_argdef = 0;} '=';
+
 block_args_tail	: f_block_kwarg ',' f_kwrest opt_f_block_arg
 		    {
 			$$ = new_args_tail(p, $1, $3, $4, &@3);
@@ -3703,6 +3712,7 @@ block_param_def	: '|' opt_bv_decl '|' https://github.com/ruby/ruby/blob/trunk/parse.y#L3712
 		    {
 			p->cur_arg = 0;
 			p->max_numparam = ORDINAL_PARAM;
+			p->ctxt.in_argdef = 0;
 		    /*%%%*/
 			$$ = 0;
 		    /*% %*/
@@ -3712,6 +3722,7 @@ block_param_def	: '|' opt_bv_decl '|' https://github.com/ruby/ruby/blob/trunk/parse.y#L3722
 		    {
 			p->cur_arg = 0;
 			p->max_numparam = ORDINAL_PARAM;
+			p->ctxt.in_argdef = 0;
 		    /*%%%*/
 			$$ = $2;
 		    /*% %*/
@@ -3792,6 +3803,7 @@ lambda		: tLAMBDA https://github.com/ruby/ruby/blob/trunk/parse.y#L3803
 
 f_larglist	: '(' f_args opt_bv_decl ')'
 		    {
+			p->ctxt.in_argdef = 0;
 		    /*%%%*/
 			$$ = $2;
 			p->max_numparam = ORDINAL_PARAM;
@@ -3800,6 +3812,7 @@ f_larglist	: '(' f_args opt_bv_decl ')' https://github.com/ruby/ruby/blob/trunk/parse.y#L3812
 		    }
 		| f_args
 		    {
+			p->ctxt.in_argdef = 0;
 		    /*%%%*/
 			if (!args_info_empty_p($1->nd_ainfo))
 			    p->max_numparam = ORDINAL_PARAM;
@@ -5122,6 +5135,7 @@ superclass	: '<' https://github.com/ruby/ruby/blob/trunk/parse.y#L5135
 f_opt_paren_args: f_paren_args
 		| none
 		    {
+			p->ctxt.in_argdef = 0;
 			$$ = new_args_tail(p, Qnone, Qnone, Qnone, &@0);
 			$$ = new_args(p, Qnone, Qnone, Qnone, Qnone, $$, &@0);
 		    }
@@ -5135,6 +5149,7 @@ f_paren_args	: '(' f_args rparen https://github.com/ruby/ruby/blob/trunk/parse.y#L5149
 		    /*% ripper: paren!($2) %*/
 			SET_LEX_STATE(EXPR_BEG);
 			p->command_start = TRUE;
+			p->ctxt.in_argdef = 0;
 		    }
                 ;
 
@@ -5142,11 +5157,13 @@ f_arglist	: f_paren_args https://github.com/ruby/ruby/blob/trunk/parse.y#L5157
 		|   {
 			$<ctxt>$ = p->ctxt;
 			p->ctxt.in_kwarg = 1;
+			p->ctxt.in_argdef = 1;
 			SET_LEX_STATE(p->lex.state|EXPR_LABEL); /* force for args */
 		    }
 		  f_args term
 		    {
 			p->ctxt.in_kwarg = $<ctxt>1.in_kwarg;
+			p->ctxt.in_argdef = 0;
 			$$ = $2;
 			SET_LEX_STATE(EXPR_BEG);
 			p->command_start = TRUE;
@@ -5363,6 +5380,7 @@ f_label 	: tLABEL https://github.com/ruby/ruby/blob/trunk/parse.y#L5380
 			arg_var(p, formal_argument(p, $1));
 			p->cur_arg = get_id($1);
 			p->max_numparam = ORDINAL_PARAM;
+			p->ctxt.in_argdef = 0;
 			$$ = $1;
 		    }
 		;
@@ -5370,6 +5388,7 @@ f_label 	: tLABEL https://github.com/ruby/ruby/blob/trunk/parse.y#L5388
 f_kw		: f_label arg_value
 		    {
 			p->cur_arg = 0;
+			p->ctxt.in_argdef = 1;
 		    /*%%%*/
 			$$ = new_kw_arg(p, assignable(p, $1, $2, &@$), &@$);
 		    /*% %*/
@@ -5378,6 +5397,7 @@ f_kw		: f_label arg_value https://github.com/ruby/ruby/blob/trunk/parse.y#L5397
 		| f_label
 		    {
 			p->cur_arg = 0;
+			p->ctxt.in_argdef = 1;
 		    /*%%%*/
 			$$ = new_kw_arg(p, assignable(p, $1, NODE_SPECIAL_REQUIRED_KEYWORD, &@$), &@$);
 		    /*% %*/
@@ -5387,6 +5407,7 @@ f_kw		: f_label arg_value https://github.com/ruby/ruby/blob/trunk/parse.y#L5407
 
 f_block_kw	: f_label primary_value
 		    {
+			p->ctxt.in_argdef = 1;
 		    /*%%%*/
 			$$ = new_kw_arg(p, assignable(p, $1, $2, &@$), &@$);
 		    /*% %*/
@@ -5394,6 +5415,7 @@ f_block_kw	: f_label primary_value https://github.com/ruby/ruby/blob/trunk/parse.y#L5415
 		    }
 		| f_label
 		    {
+			p->ctxt.in_argdef = 1;
 		    /*%%%*/
 			$$ = new_kw_arg(p, assignable(p, $1, NODE_SPECIAL_REQUIRED_KEYWORD, &@$), &@$);
 		    /*% %*/
@@ -5464,9 +5486,10 @@ f_kwrest	: kwrest_mark tIDENTIFIER https://github.com/ruby/ruby/blob/trunk/parse.y#L5486
 		    }
 		;
 
-f_opt		: f_arg_asgn '=' arg_value
+f_opt		: f_arg_asgn f_eq arg_value
 		    {
 			p->cur_arg = 0;
+			p->ctxt.in_argdef = 1;
 		    /*%%%*/
 			$$ = NEW_OPT_ARG(0, assignable(p, $1, $3, &@$), &@$);
 		    /*% %*/
@@ -5474,9 +5497,10 @@ f_opt		: f_arg_asgn '=' arg_value https://github.com/ruby/ruby/blob/trunk/parse.y#L5497
 		    }
 		;
 
-f_block_opt	: f_arg_asgn '=' primary_value
+f_block_opt	: f_arg_asgn f_eq primary_value
 		    {
 			p->cur_arg = 0;
+			p->ctxt.in_argdef = 1;
 		    /*%%%*/
 			$$ = NEW_OPT_ARG(0, assignable(p, $1, $3, &@$), &@$);
 		    /*% %*/
@@ -9659,13 +9683,11 @@ parser_yylex(struct parser_params *p) https://github.com/ruby/ruby/blob/trunk/parse.y#L9683
 	SET_LEX_STATE(EXPR_BEG);
 	if ((c = nextc(p)) == '.') {
 	    if ((c = nextc(p)) == '.') {
+		if (p->ctxt.in_argdef) {
+		    SET_LEX_STATE(EXPR_ENDARG);
+		    return tBDOT3;
+		}
 		if (p->lex.paren_nest == 0 && looking_at_eol_p(p)) {
-		    if (p->ctxt.in_argdef || /* def foo a, ... */
-			IS_lex_state_for(last_state, EXPR_ENDFN) || /* def foo ... */
-			0) {
-			SET_LEX_STATE(EXPR_ENDARG);
-			return tBDOT3;
-		    }
 		    rb_warn0("... at EOL, should be parenthesized?");
 		}
 		else if (p->lex.lpar_beg >= 0 && p->lex.lpar_beg+1 == p->lex.paren_nest) {
diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb
index ce1e489992e..b71f492f9cc 100644
--- a/test/ruby/test_syntax.rb
+++ b/test/ruby/test_syntax.rb
@@ -1587,7 +1587,15 @@ eom https://github.com/ruby/ruby/blob/trunk/test/ruby/test_syntax.rb#L1587
   def test_argument_forwarding
     assert_valid_syntax('def foo(...) bar(...) end')
     assert_valid_syntax('def foo(...) end')
+    assert_valid_syntax('def foo(a, ...) bar(...) end')
     assert_valid_syntax("def foo ...\n  bar(...)\nend")
+    assert_valid_syntax("def foo a, ...\n  bar(...)\nend")
+    assert_valid_syntax("def foo b = 1, ...\n  bar(...)\nend")
+    assert_valid_syntax("def foo ...; bar(...); end")
+    assert_valid_syntax("def foo a, ...; bar(...); end")
+    assert_valid_syntax("def foo b = 1, ...; bar(...); end")
+    assert_valid_syntax("(def foo ...\n  bar(...)\nend)")
+    assert_valid_syntax("(def foo ...; bar(...); end)")
     assert_valid_syntax('def ==(...) end')
     assert_valid_syntax('def [](...) end')
     assert_valid_syntax('def nil(...) end')
@@ -1618,8 +1626,10 @@ eom https://github.com/ruby/ruby/blob/trunk/test/ruby/test_syntax.rb#L1626
       end
     end
     obj4 = obj1.clone
+    obj5 = obj1.clone
     obj1.instance_eval('def foo(...) bar(...) end', __FILE__, __LINE__)
     obj4.instance_eval("def foo ...\n  bar(...)\n""end", __FILE__, __LINE__)
+    obj5.instance_eval("def foo ...; bar(...); end", __FILE__, __LINE__)
 
     klass = Class.new {
       def foo(*args, **kws, &block)
@@ -1648,7 +1658,7 @@ eom https://github.com/ruby/ruby/blob/trunk/test/ruby/test_syntax.rb#L1658
     end
     obj3.instance_eval('def foo(...) bar(...) end', __FILE__, __LINE__)
 
-    [obj1, obj2, obj3, obj4].each do |obj|
+    [obj1, obj2, obj3, obj4, obj5].each do |obj|
       assert_warning('') {
         assert_equal([[1, 2, 3], {k1: 4, k2: 5}], obj.foo(1, 2, 3, k1: 4, k2: 5) {|*x| x})
       }
@@ -1791,6 +1801,19 @@ eom https://github.com/ruby/ruby/blob/trunk/test/ruby/test_syntax.rb#L1801
     assert_equal [[4, 2], {a: 1}], obj.foo(4, 2, a: 1)
     assert_equal [[4, 2, 3], {a: 1}], obj.foo(4, 2, 3, a: 1)
     assert_equal [[4, 2, 3], {a: 1}], obj.foo(4, 2, 3, a: 1){|args, kws| [args, kws]}
+
+    obj.singleton_class.send(:remove_method, :foo)
+    obj.instance_eval("def foo a, ...; bar(a, ...); end", __FILE__, __LINE__)
+    assert_equal [[4], {}], obj.foo(4)
+    assert_equal [[4, 2], {}], obj.foo(4, 2)
+    assert_equal [[4, 2, 3], {}], obj.foo(4, 2, 3)
+    assert_equal [[4], {a: 1}], obj.foo(4, a: 1)
+    assert_equal [[4, 2], {a: 1}], obj.foo(4, 2, a: 1)
+    assert_equal [[4, 2, 3], {a: 1}], obj.foo(4, 2, 3, a: 1)
+    assert_equal [[4, 2, 3], {a: 1}], obj.foo(4, 2, 3, a: 1){|args, kws| [args, kws]}
+
+    exp = eval("-> (a: nil) {a...1}")
+    assert_equal 0...1, exp.call(a: 0)
   end
 
   def test_cdhash
-- 
cgit v1.2.1


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

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