summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTSUYUSATO Kitsune <make.just.on@gmail.com>2023-12-27 12:05:04 +0900
committergit <svn-admin@ruby-lang.org>2024-01-02 19:08:15 +0000
commit0ee625ceae004f2ca53ebe234310ff2d44f7388c (patch)
tree80528bc06409335ad289d7ce09d1135e81b23973
parent165deec5fef5076bca99c038caf8c9da34abe0fd (diff)
[ruby/prism] Fix to check multiple block arguments for forwarding arg
Fix https://github.com/ruby/prism/pull/2111 https://github.com/ruby/prism/commit/21ca243d0a
-rw-r--r--prism/diagnostic.c1
-rw-r--r--prism/diagnostic.h1
-rw-r--r--prism/prism.c20
-rw-r--r--test/prism/errors_test.rb14
4 files changed, 31 insertions, 5 deletions
diff --git a/prism/diagnostic.c b/prism/diagnostic.c
index fd5dce5a04..c779955eb3 100644
--- a/prism/diagnostic.c
+++ b/prism/diagnostic.c
@@ -56,6 +56,7 @@ static const char* const diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = {
[PM_ERR_ARGUMENT_AFTER_BLOCK] = "unexpected argument after a block argument",
[PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES] = "unexpected argument after `...`",
[PM_ERR_ARGUMENT_BARE_HASH] = "unexpected bare hash argument",
+ [PM_ERR_ARGUMENT_BLOCK_FORWARDING] = "both a block argument and a forwarding argument; only one block is allowed",
[PM_ERR_ARGUMENT_BLOCK_MULTI] = "multiple block arguments; only one block is allowed",
[PM_ERR_ARGUMENT_FORMAL_CLASS] = "invalid formal argument; formal argument cannot be a class variable",
[PM_ERR_ARGUMENT_FORMAL_CONSTANT] = "invalid formal argument; formal argument cannot be a constant",
diff --git a/prism/diagnostic.h b/prism/diagnostic.h
index 08a3284abf..da430b5438 100644
--- a/prism/diagnostic.h
+++ b/prism/diagnostic.h
@@ -47,6 +47,7 @@ typedef enum {
PM_ERR_ARGUMENT_AFTER_BLOCK,
PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES,
PM_ERR_ARGUMENT_BARE_HASH,
+ PM_ERR_ARGUMENT_BLOCK_FORWARDING,
PM_ERR_ARGUMENT_BLOCK_MULTI,
PM_ERR_ARGUMENT_FORMAL_CLASS,
PM_ERR_ARGUMENT_FORMAL_CONSTANT,
diff --git a/prism/prism.c b/prism/prism.c
index 03df698449..29505a9646 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -813,6 +813,9 @@ typedef struct {
/** The optional block attached to the call. */
pm_node_t *block;
+
+ /** The flag indicating whether this arguments list has forwarding argument. */
+ bool has_forwarding;
} pm_arguments_t;
/**
@@ -11306,6 +11309,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
argument = (pm_node_t *) pm_forwarding_arguments_node_create(parser, &parser->previous);
parse_arguments_append(parser, arguments, argument);
+ arguments->has_forwarding = true;
parsed_forwarding_arguments = true;
break;
}
@@ -12170,14 +12174,20 @@ parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accept
}
if (block != NULL) {
- if (arguments->block == NULL) {
+ if (arguments->block == NULL && !arguments->has_forwarding) {
arguments->block = (pm_node_t *) block;
} else {
- pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_MULTI);
- if (arguments->arguments == NULL) {
- arguments->arguments = pm_arguments_node_create(parser);
+ if (arguments->has_forwarding) {
+ pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_FORWARDING);
+ } else {
+ pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_MULTI);
+ }
+ if (arguments->block != NULL) {
+ if (arguments->arguments == NULL) {
+ arguments->arguments = pm_arguments_node_create(parser);
+ }
+ pm_arguments_node_arguments_append(arguments->arguments, arguments->block);
}
- pm_arguments_node_arguments_append(arguments->arguments, arguments->block);
arguments->block = (pm_node_t *) block;
}
}
diff --git a/test/prism/errors_test.rb b/test/prism/errors_test.rb
index 57c0719aa7..7648875691 100644
--- a/test/prism/errors_test.rb
+++ b/test/prism/errors_test.rb
@@ -2046,6 +2046,20 @@ module Prism
]
end
+ def test_block_arg_and_block
+ source = 'foo(&1) { }'
+ assert_errors expression(source), source, [
+ ['multiple block arguments; only one block is allowed', 8..11]
+ ], compare_ripper: false # Ripper does not check 'both block arg and actual block given'.
+ end
+
+ def test_forwarding_arg_and_block
+ source = 'def foo(...) = foo(...) { }'
+ assert_errors expression(source), source, [
+ ['both a block argument and a forwarding argument; only one block is allowed', 24..27]
+ ], compare_ripper: false # Ripper does not check 'both block arg and actual block given'.
+ end
+
private
def assert_errors(expected, source, errors, compare_ripper: RUBY_ENGINE == "ruby")