summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2025-10-24 00:57:26 +0900
committerNobuyoshi Nakada <nobu.nakada@gmail.com>2025-11-14 21:03:04 +0900
commitf4b6a5191ceb0ed0cd7a3e3c8bab24cc0dd15736 (patch)
tree8b25e2ca6674ee51a4d1b306c5df392c128d85bc
parent6f18898f4902b2717442f9bef4faa876d58f99de (diff)
[Feature #21572] Syntax error at capture in alternation pattern
Should fail even with `-c` option.
-rw-r--r--parse.y32
-rw-r--r--prism/config.yml2
-rw-r--r--prism/prism.c69
-rw-r--r--prism/templates/src/diagnostic.c.erb2
-rw-r--r--spec/ruby/language/pattern_matching_spec.rb2
-rw-r--r--test/prism/result/source_location_test.rb2
-rw-r--r--test/ruby/test_pattern_matching.rb19
7 files changed, 95 insertions, 33 deletions
diff --git a/parse.y b/parse.y
index bca6e342ae..f6222ea52e 100644
--- a/parse.y
+++ b/parse.y
@@ -318,6 +318,8 @@ struct lex_context {
BITFIELD(enum rb_parser_shareability, shareable_constant_value, 2);
BITFIELD(enum rescue_context, in_rescue, 2);
unsigned int cant_return: 1;
+ unsigned int in_alt_pattern: 1;
+ unsigned int capture_in_pattern: 1;
};
typedef struct RNode_DEF_TEMP rb_node_def_temp_t;
@@ -3473,6 +3475,8 @@ expr : command_call
pop_pktbl(p, $p_pktbl);
pop_pvtbl(p, $p_pvtbl);
p->ctxt.in_kwarg = $ctxt.in_kwarg;
+ p->ctxt.in_alt_pattern = $ctxt.in_alt_pattern;
+ p->ctxt.capture_in_pattern = $ctxt.capture_in_pattern;
$$ = NEW_CASE3($arg, NEW_IN($body, 0, 0, &@body, &NULL_LOC, &NULL_LOC, &@2), &@$, &NULL_LOC, &NULL_LOC);
/*% ripper: case!($:arg, in!($:body, Qnil, Qnil)) %*/
}
@@ -3486,6 +3490,8 @@ expr : command_call
pop_pktbl(p, $p_pktbl);
pop_pvtbl(p, $p_pvtbl);
p->ctxt.in_kwarg = $ctxt.in_kwarg;
+ p->ctxt.in_alt_pattern = $ctxt.in_alt_pattern;
+ p->ctxt.capture_in_pattern = $ctxt.capture_in_pattern;
$$ = NEW_CASE3($arg, NEW_IN($body, NEW_TRUE(&@body), NEW_FALSE(&@body), &@body, &@keyword_in, &NULL_LOC, &NULL_LOC), &@$, &NULL_LOC, &NULL_LOC);
/*% ripper: case!($:arg, in!($:body, Qnil, Qnil)) %*/
}
@@ -5389,6 +5395,8 @@ p_in_kwarg : {
SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
p->command_start = FALSE;
p->ctxt.in_kwarg = 1;
+ p->ctxt.in_alt_pattern = 0;
+ p->ctxt.capture_in_pattern = 0;
}
;
@@ -5399,6 +5407,8 @@ p_case_body : keyword_in
pop_pktbl(p, $p_pktbl);
pop_pvtbl(p, $p_pvtbl);
p->ctxt.in_kwarg = $ctxt.in_kwarg;
+ p->ctxt.in_alt_pattern = $ctxt.in_alt_pattern;
+ p->ctxt.capture_in_pattern = $ctxt.capture_in_pattern;
}
compstmt(stmts)
p_cases[cases]
@@ -5458,6 +5468,11 @@ p_top_expr_body : p_expr
;
p_expr : p_as
+ {
+ p->ctxt.in_alt_pattern = 0;
+ p->ctxt.capture_in_pattern = 0;
+ $$ = $1;
+ }
;
p_as : p_expr tASSOC p_variable
@@ -5470,10 +5485,17 @@ p_as : p_expr tASSOC p_variable
| p_alt
;
-p_alt : p_alt '|' p_expr_basic
+p_alt : p_alt[left] '|'[alt]
{
- $$ = NEW_OR($1, $3, &@$, &@2);
- /*% ripper: binary!($:1, ID2VAL(idOr), $:3) %*/
+ p->ctxt.in_alt_pattern = 1;
+ }
+ p_expr_basic[right]
+ {
+ if (p->ctxt.capture_in_pattern) {
+ yyerror1(&@alt, "alternative pattern after variable capture");
+ }
+ $$ = NEW_OR($left, $right, &@$, &@alt);
+ /*% ripper: binary!($:left, ID2VAL(idOr), $:right) %*/
}
| p_expr_basic
;
@@ -14697,7 +14719,11 @@ error_duplicate_pattern_variable(struct parser_params *p, ID id, const YYLTYPE *
if (st_is_member(p->pvtbl, id)) {
yyerror1(loc, "duplicated variable name");
}
+ else if (p->ctxt.in_alt_pattern && id) {
+ yyerror1(loc, "variable capture in alternative pattern");
+ }
else {
+ p->ctxt.capture_in_pattern = 1;
st_insert(p->pvtbl, (st_data_t)id, 0);
}
}
diff --git a/prism/config.yml b/prism/config.yml
index 7d71d52de4..879130d735 100644
--- a/prism/config.yml
+++ b/prism/config.yml
@@ -217,8 +217,10 @@ errors:
- PARAMETER_UNEXPECTED_FWD
- PARAMETER_UNEXPECTED_NO_KW
- PARAMETER_WILD_LOOSE_COMMA
+ - PATTERN_ALTERNATIVE_AFTER_CAPTURE
- PATTERN_ARRAY_MULTIPLE_RESTS
- PATTERN_CAPTURE_DUPLICATE
+ - PATTERN_CAPTURE_IN_ALTERNATIVE
- PATTERN_EXPRESSION_AFTER_BRACKET
- PATTERN_EXPRESSION_AFTER_COMMA
- PATTERN_EXPRESSION_AFTER_HROCKET
diff --git a/prism/prism.c b/prism/prism.c
index 02dd2f1175..9e6d9d4483 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -16937,6 +16937,11 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1
#define PM_PARSE_PATTERN_TOP 1
#define PM_PARSE_PATTERN_MULTI 2
+typedef struct {
+ bool in_alternative_pattern;
+ bool capture_in_pattern;
+} pm_pattern_capturing_t;
+
static pm_node_t *
parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth);
@@ -16946,13 +16951,16 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
* an error to the parser.
*/
static void
-parse_pattern_capture(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_constant_id_t capture, const pm_location_t *location) {
+parse_pattern_capture(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_constant_id_t capture, const pm_location_t *location, pm_pattern_capturing_t *capturing) {
// Skip this capture if it starts with an underscore.
if (*location->start == '_') return;
if (pm_constant_id_list_includes(captures, capture)) {
pm_parser_err(parser, location->start, location->end, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
+ } else if (capturing->in_alternative_pattern && parser->version >= PM_OPTIONS_VERSION_CRUBY_3_5) {
+ pm_parser_err(parser, location->start, location->end, PM_ERR_PATTERN_CAPTURE_IN_ALTERNATIVE);
} else {
+ capturing->capture_in_pattern = true;
pm_constant_id_list_append(captures, capture);
}
}
@@ -17081,7 +17089,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
* Parse a rest pattern.
*/
static pm_splat_node_t *
-parse_pattern_rest(pm_parser_t *parser, pm_constant_id_list_t *captures) {
+parse_pattern_rest(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_pattern_capturing_t *capturing) {
assert(parser->previous.type == PM_TOKEN_USTAR);
pm_token_t operator = parser->previous;
pm_node_t *name = NULL;
@@ -17098,7 +17106,7 @@ parse_pattern_rest(pm_parser_t *parser, pm_constant_id_list_t *captures) {
pm_parser_local_add(parser, constant_id, identifier.start, identifier.end, 0);
}
- parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&identifier));
+ parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&identifier), capturing);
name = (pm_node_t *) pm_local_variable_target_node_create(
parser,
&PM_LOCATION_TOKEN_VALUE(&identifier),
@@ -17115,7 +17123,7 @@ parse_pattern_rest(pm_parser_t *parser, pm_constant_id_list_t *captures) {
* Parse a keyword rest node.
*/
static pm_node_t *
-parse_pattern_keyword_rest(pm_parser_t *parser, pm_constant_id_list_t *captures) {
+parse_pattern_keyword_rest(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_pattern_capturing_t *capturing) {
assert(parser->current.type == PM_TOKEN_USTAR_STAR);
parser_lex(parser);
@@ -17134,7 +17142,7 @@ parse_pattern_keyword_rest(pm_parser_t *parser, pm_constant_id_list_t *captures)
pm_parser_local_add(parser, constant_id, parser->previous.start, parser->previous.end, 0);
}
- parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->previous));
+ parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->previous), capturing);
value = (pm_node_t *) pm_local_variable_target_node_create(
parser,
&PM_LOCATION_TOKEN_VALUE(&parser->previous),
@@ -17178,7 +17186,7 @@ pm_slice_is_valid_local(const pm_parser_t *parser, const uint8_t *start, const u
* value. This will use an implicit local variable target.
*/
static pm_node_t *
-parse_pattern_hash_implicit_value(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_symbol_node_t *key) {
+parse_pattern_hash_implicit_value(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_symbol_node_t *key, pm_pattern_capturing_t *capturing) {
const pm_location_t *value_loc = &((pm_symbol_node_t *) key)->value_loc;
pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, value_loc->start, value_loc->end);
@@ -17198,7 +17206,7 @@ parse_pattern_hash_implicit_value(pm_parser_t *parser, pm_constant_id_list_t *ca
pm_parser_local_add(parser, constant_id, value_loc->start, value_loc->end, 0);
}
- parse_pattern_capture(parser, captures, constant_id, value_loc);
+ parse_pattern_capture(parser, captures, constant_id, value_loc, capturing);
pm_local_variable_target_node_t *target = pm_local_variable_target_node_create(
parser,
value_loc,
@@ -17224,7 +17232,7 @@ parse_pattern_hash_key(pm_parser_t *parser, pm_static_literals_t *keys, pm_node_
* Parse a hash pattern.
*/
static pm_hash_pattern_node_t *
-parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node_t *first_node, uint16_t depth) {
+parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node_t *first_node, pm_pattern_capturing_t *capturing, uint16_t depth) {
pm_node_list_t assocs = { 0 };
pm_static_literals_t keys = { 0 };
pm_node_t *rest = NULL;
@@ -17242,7 +17250,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
if (match8(parser, PM_TOKEN_COMMA, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_EOF)) {
// Otherwise, we will create an implicit local variable
// target for the value.
- value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) first_node);
+ value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) first_node, capturing);
} else {
// Here we have a value for the first assoc in the list, so
// we will parse it now.
@@ -17286,7 +17294,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
}
if (match1(parser, PM_TOKEN_USTAR_STAR)) {
- pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
+ pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures, capturing);
if (rest == NULL) {
rest = assoc;
@@ -17314,7 +17322,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
pm_node_t *value = NULL;
if (match7(parser, PM_TOKEN_COMMA, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
- value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) key);
+ value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) key, capturing);
} else {
value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
}
@@ -17341,7 +17349,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
* Parse a pattern expression primitive.
*/
static pm_node_t *
-parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_diagnostic_id_t diag_id, uint16_t depth) {
+parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_pattern_capturing_t *capturing, pm_diagnostic_id_t diag_id, uint16_t depth) {
switch (parser->current.type) {
case PM_TOKEN_IDENTIFIER:
case PM_TOKEN_METHOD_NAME: {
@@ -17353,7 +17361,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
pm_parser_local_add(parser, constant_id, parser->previous.start, parser->previous.end, 0);
}
- parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->previous));
+ parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->previous), capturing);
return (pm_node_t *) pm_local_variable_target_node_create(
parser,
&PM_LOCATION_TOKEN_VALUE(&parser->previous),
@@ -17437,7 +17445,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
first_node = (pm_node_t *) pm_symbol_node_label_create(parser, &parser->previous);
break;
case PM_TOKEN_USTAR_STAR:
- first_node = parse_pattern_keyword_rest(parser, captures);
+ first_node = parse_pattern_keyword_rest(parser, captures, capturing);
break;
case PM_TOKEN_STRING_BEGIN:
first_node = parse_expression(parser, PM_BINDING_POWER_MAX, false, true, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
@@ -17451,7 +17459,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
}
}
- node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
+ node = parse_pattern_hash(parser, captures, first_node, capturing, (uint16_t) (depth + 1));
accept1(parser, PM_TOKEN_NEWLINE);
expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE);
@@ -17619,10 +17627,18 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
static pm_node_t *
parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node_t *first_node, pm_diagnostic_id_t diag_id, uint16_t depth) {
pm_node_t *node = first_node;
+ pm_pattern_capturing_t capturing = { false, false };
while ((node == NULL) || accept1(parser, PM_TOKEN_PIPE)) {
pm_token_t operator = parser->previous;
+ if (node) {
+ if (capturing.capture_in_pattern) {
+ pm_parser_err(parser, operator.start, operator.end, PM_ERR_PATTERN_ALTERNATIVE_AFTER_CAPTURE);
+ }
+ capturing.in_alternative_pattern = true;
+ }
+
switch (parser->current.type) {
case PM_TOKEN_IDENTIFIER:
case PM_TOKEN_BRACKET_LEFT_ARRAY:
@@ -17634,9 +17650,9 @@ parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, p
case PM_TOKEN_UDOT_DOT_DOT:
case PM_CASE_PRIMITIVE: {
if (node == NULL) {
- node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
+ node = parse_pattern_primitive(parser, captures, &capturing, diag_id, (uint16_t) (depth + 1));
} else {
- pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
+ pm_node_t *right = parse_pattern_primitive(parser, captures, &capturing, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
node = (pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &operator);
}
@@ -17688,7 +17704,7 @@ parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, p
pm_parser_local_add(parser, constant_id, parser->previous.start, parser->previous.end, 0);
}
- parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->previous));
+ parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->previous), &capturing);
pm_local_variable_target_node_t *target = pm_local_variable_target_node_create(
parser,
&PM_LOCATION_TOKEN_VALUE(&parser->previous),
@@ -17711,12 +17727,13 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
bool leading_rest = false;
bool trailing_rest = false;
+ pm_pattern_capturing_t capturing = { false, false };
switch (parser->current.type) {
case PM_TOKEN_LABEL: {
parser_lex(parser);
pm_node_t *key = (pm_node_t *) pm_symbol_node_label_create(parser, &parser->previous);
- node = (pm_node_t *) parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1));
+ node = (pm_node_t *) parse_pattern_hash(parser, captures, key, &capturing, (uint16_t) (depth + 1));
if (!(flags & PM_PARSE_PATTERN_TOP)) {
pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
@@ -17725,8 +17742,8 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
return node;
}
case PM_TOKEN_USTAR_STAR: {
- node = parse_pattern_keyword_rest(parser, captures);
- node = (pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
+ node = parse_pattern_keyword_rest(parser, captures, &capturing);
+ node = (pm_node_t *) parse_pattern_hash(parser, captures, node, &capturing, (uint16_t) (depth + 1));
if (!(flags & PM_PARSE_PATTERN_TOP)) {
pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
@@ -17737,10 +17754,10 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
case PM_TOKEN_STRING_BEGIN: {
// We need special handling for string beginnings because they could
// be dynamic symbols leading to hash patterns.
- node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
+ node = parse_pattern_primitive(parser, captures, &capturing, diag_id, (uint16_t) (depth + 1));
if (pm_symbol_node_label_p(node)) {
- node = (pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
+ node = (pm_node_t *) parse_pattern_hash(parser, captures, node, &capturing, (uint16_t) (depth + 1));
if (!(flags & PM_PARSE_PATTERN_TOP)) {
pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
@@ -17755,7 +17772,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
case PM_TOKEN_USTAR: {
if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
parser_lex(parser);
- node = (pm_node_t *) parse_pattern_rest(parser, captures);
+ node = (pm_node_t *) parse_pattern_rest(parser, captures, &capturing);
leading_rest = true;
break;
}
@@ -17769,7 +17786,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
// If we got a dynamic label symbol, then we need to treat it like the
// beginning of a hash pattern.
if (pm_symbol_node_label_p(node)) {
- return (pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
+ return (pm_node_t *) parse_pattern_hash(parser, captures, node, &capturing, (uint16_t) (depth + 1));
}
if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
@@ -17790,7 +17807,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
}
if (accept1(parser, PM_TOKEN_USTAR)) {
- node = (pm_node_t *) parse_pattern_rest(parser, captures);
+ node = (pm_node_t *) parse_pattern_rest(parser, captures, &capturing);
// If we have already parsed a splat pattern, then this is an
// error. We will continue to parse the rest of the patterns,
diff --git a/prism/templates/src/diagnostic.c.erb b/prism/templates/src/diagnostic.c.erb
index 2373253085..b06fcafb4a 100644
--- a/prism/templates/src/diagnostic.c.erb
+++ b/prism/templates/src/diagnostic.c.erb
@@ -299,8 +299,10 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_ERR_PARAMETER_UNEXPECTED_FWD] = { "unexpected `...` in parameters", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PARAMETER_WILD_LOOSE_COMMA] = { "unexpected `,` in parameters", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PARAMETER_UNEXPECTED_NO_KW] = { "unexpected **nil; no keywords marker disallowed after keywords", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_PATTERN_ALTERNATIVE_AFTER_CAPTURE] = { "alternative pattern after variable capture", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS] = { "unexpected multiple '*' rest patterns in an array pattern", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PATTERN_CAPTURE_DUPLICATE] = { "duplicated variable name", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_PATTERN_CAPTURE_IN_ALTERNATIVE] = { "variable capture in alternative pattern", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET] = { "expected a pattern expression after the `[` operator", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA] = { "expected a pattern expression after `,`", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PATTERN_EXPRESSION_AFTER_HROCKET] = { "expected a pattern expression after `=>`", PM_ERROR_LEVEL_SYNTAX },
diff --git a/spec/ruby/language/pattern_matching_spec.rb b/spec/ruby/language/pattern_matching_spec.rb
index cb4f5864d7..c1a6f0e4d6 100644
--- a/spec/ruby/language/pattern_matching_spec.rb
+++ b/spec/ruby/language/pattern_matching_spec.rb
@@ -493,7 +493,7 @@ describe "Pattern matching" do
in [0, 0] | [0, a]
end
RUBY
- }.should raise_error(SyntaxError, /illegal variable in alternative pattern/)
+ }.should raise_error(SyntaxError)
end
it "support underscore prefixed variables in alternation" do
diff --git a/test/prism/result/source_location_test.rb b/test/prism/result/source_location_test.rb
index 7bdc707658..38b971d02b 100644
--- a/test/prism/result/source_location_test.rb
+++ b/test/prism/result/source_location_test.rb
@@ -13,7 +13,7 @@ module Prism
end
def test_AlternationPatternNode
- assert_location(AlternationPatternNode, "foo => bar | baz", 7...16, &:pattern)
+ assert_location(AlternationPatternNode, "foo => 0 | 1", 7...12, &:pattern)
end
def test_AndNode
diff --git a/test/ruby/test_pattern_matching.rb b/test/ruby/test_pattern_matching.rb
index 92a3244fc2..77f1cb3972 100644
--- a/test/ruby/test_pattern_matching.rb
+++ b/test/ruby/test_pattern_matching.rb
@@ -197,11 +197,26 @@ class TestPatternMatching < Test::Unit::TestCase
end
end
- assert_syntax_error(%q{
+ assert_valid_syntax(%{
+ case 0
+ in [ :a | :b, x]
+ true
+ end
+ })
+
+ assert_in_out_err(['-c'], %q{
case 0
in a | 0
end
- }, /illegal variable in alternative pattern/)
+ }, [], /alternative pattern after variable capture/,
+ success: false)
+
+ assert_in_out_err(['-c'], %q{
+ case 0
+ in 0 | a
+ end
+ }, [], /variable capture in alternative pattern/,
+ success: false)
end
def test_var_pattern