[ruby/prism] Fix error message for block/lambda with ... argument

They currently complain that the parent method is not forwarding.
But the actual problem is that these types of arguments simply don't
accept `...`

Fixes [Bug #21927]

https://github.com/ruby/prism/commit/0aa2363331
This commit is contained in:
Earlopain 2026-02-27 11:51:22 +01:00 committed by Takashi Kokubun
parent 83c261f30b
commit e7d2828fb6
5 changed files with 51 additions and 5 deletions

View File

@ -17,6 +17,8 @@ errors:
- ARGUMENT_FORWARDING_UNBOUND
- ARGUMENT_NO_FORWARDING_AMPERSAND
- ARGUMENT_NO_FORWARDING_ELLIPSES
- ARGUMENT_NO_FORWARDING_ELLIPSES_LAMBDA
- ARGUMENT_NO_FORWARDING_ELLIPSES_BLOCK
- ARGUMENT_NO_FORWARDING_STAR
- ARGUMENT_NO_FORWARDING_STAR_STAR
- ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT

View File

@ -13876,6 +13876,7 @@ parse_parameters(
bool allows_forwarding_parameters,
bool accepts_blocks_in_defaults,
bool in_block,
pm_diagnostic_id_t diag_id_forwarding,
uint16_t depth
) {
pm_do_loop_stack_push(parser, false);
@ -13931,7 +13932,7 @@ parse_parameters(
}
case PM_TOKEN_UDOT_DOT_DOT: {
if (!allows_forwarding_parameters) {
pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
pm_parser_err_current(parser, diag_id_forwarding);
}
bool succeeded = update_parameter_state(parser, &parser->current, &order);
@ -14611,6 +14612,7 @@ parse_block_parameters(
false,
accepts_blocks_in_defaults,
true,
is_lambda_literal ? PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_LAMBDA : PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_BLOCK,
(uint16_t) (depth + 1)
);
if (!is_lambda_literal) {
@ -18853,7 +18855,17 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
params = NULL;
} else {
params = parse_parameters(parser, PM_BINDING_POWER_DEFINED, true, false, true, true, false, (uint16_t) (depth + 1));
params = parse_parameters(
parser,
PM_BINDING_POWER_DEFINED,
true,
false,
true,
true,
false,
PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
(uint16_t) (depth + 1)
);
}
lex_state_set(parser, PM_LEX_STATE_BEG);
@ -18878,7 +18890,17 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
lparen = not_provided(parser);
rparen = not_provided(parser);
params = parse_parameters(parser, PM_BINDING_POWER_DEFINED, false, false, true, true, false, (uint16_t) (depth + 1));
params = parse_parameters(
parser,
PM_BINDING_POWER_DEFINED,
false,
false,
true,
true,
false,
PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
(uint16_t) (depth + 1)
);
// Reject `def * = 1` and similar. We have to specifically check
// for them because they create ambiguity with optional arguments.

View File

@ -102,6 +102,8 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_ERR_ARGUMENT_FORWARDING_UNBOUND] = { "unexpected `...` in an non-parenthesized call", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND] = { "unexpected `&`; no anonymous block parameter", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES] = { "unexpected ... when the parent method is not forwarding", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_LAMBDA] = { "unexpected ... in lambda argument", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_BLOCK] = { "unexpected ... in block argument", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_NO_FORWARDING_STAR] = { "unexpected `*`; no anonymous rest parameter", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR] = { "unexpected `**`; no anonymous keyword rest parameter", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT] = { "unexpected `*` splat argument after a `**` keyword splat argument", PM_ERROR_LEVEL_SYNTAX },

View File

@ -1,3 +1,13 @@
a {|...|}
^~~ unexpected ... when the parent method is not forwarding
^~~ unexpected ... in block argument
def foo(...)
a {|...|}
^~~ unexpected ... in block argument
end
def foo
a {|...|}
^~~ unexpected ... in block argument
end

View File

@ -1,3 +1,13 @@
->(...) {}
^~~ unexpected ... when the parent method is not forwarding
^~~ unexpected ... in lambda argument
def foo(...)
->(...) {}
^~~ unexpected ... in lambda argument
end
def foo
->(...) {}
^~~ unexpected ... in lambda argument
end