From a9f096183170810ac6ce32b20d7810d11a51b5f5 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Sat, 23 Dec 2023 18:07:37 +0900 Subject: [PATCH] [Feature #19370] Prohibit nesting anonymous parameter forwarding --- parse.y | 6 ++++++ test/ruby/test_syntax.rb | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/parse.y b/parse.y index 75b7151e60197c..f8e21dc9a3c1d8 100644 --- a/parse.y +++ b/parse.y @@ -15009,6 +15009,8 @@ add_forwarding_args(struct parser_params *p) static void forwarding_arg_check(struct parser_params *p, ID arg, ID all, const char *var) { + bool conflict = false; + struct vtable *vars, *args; vars = p->lvtbl->vars; @@ -15017,6 +15019,7 @@ forwarding_arg_check(struct parser_params *p, ID arg, ID all, const char *var) while (vars && !DVARS_TERMINAL_P(vars->prev)) { vars = vars->prev; args = args->prev; + conflict |= (vtable_included(args, arg) && !(all && vtable_included(args, all))); } bool found = false; @@ -15032,6 +15035,9 @@ forwarding_arg_check(struct parser_params *p, ID arg, ID all, const char *var) if (!found) { compile_error(p, "no anonymous %s parameter", var); } + else if (conflict) { + compile_error(p, "anonymous %s parameter is also used within block", var); + } } #ifndef RIPPER diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb index 7bbb14e3239ae8..33fcc6a1e024aa 100644 --- a/test/ruby/test_syntax.rb +++ b/test/ruby/test_syntax.rb @@ -76,6 +76,7 @@ def test_script_lines_encoding def test_anonymous_block_forwarding assert_syntax_error("def b; c(&); end", /no anonymous block parameter/) + assert_syntax_error("def b(&) ->(&) {c(&)} end", /anonymous block parameter is also used/) assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}") begin; def b(&); c(&) end @@ -143,6 +144,9 @@ def all_kwrest(arg1, arg2, *rest, post1, post2, kw1: 1, kw2: 2, okw1:, okw2:, ** def test_anonymous_rest_forwarding assert_syntax_error("def b; c(*); end", /no anonymous rest parameter/) assert_syntax_error("def b; c(1, *); end", /no anonymous rest parameter/) + assert_syntax_error("def b(*) ->(*) {c(*)} end", /anonymous rest parameter is also used/) + assert_syntax_error("def b(a, *) ->(*) {c(1, *)} end", /anonymous rest parameter is also used/) + assert_syntax_error("def b(*) ->(a, *) {c(*)} end", /anonymous rest parameter is also used/) assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}") begin; def b(*); c(*) end @@ -156,6 +160,9 @@ def d(*); b(*, *) end def test_anonymous_keyword_rest_forwarding assert_syntax_error("def b; c(**); end", /no anonymous keyword rest parameter/) assert_syntax_error("def b; c(k: 1, **); end", /no anonymous keyword rest parameter/) + assert_syntax_error("def b(**) ->(**) {c(**)} end", /anonymous keyword rest parameter is also used/) + assert_syntax_error("def b(k:, **) ->(**) {c(k: 1, **)} end", /anonymous keyword rest parameter is also used/) + assert_syntax_error("def b(**) ->(k:, **) {c(**)} end", /anonymous keyword rest parameter is also used/) assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}") begin; def b(**); c(**) end