diff options
| author | Nobuyoshi Nakada <nobu@ruby-lang.org> | 2025-10-24 00:57:26 +0900 |
|---|---|---|
| committer | Nobuyoshi Nakada <nobu.nakada@gmail.com> | 2025-11-14 21:03:04 +0900 |
| commit | f4b6a5191ceb0ed0cd7a3e3c8bab24cc0dd15736 (patch) | |
| tree | 8b25e2ca6674ee51a4d1b306c5df392c128d85bc | |
| parent | 6f18898f4902b2717442f9bef4faa876d58f99de (diff) | |
[Feature #21572] Syntax error at capture in alternation pattern
Should fail even with `-c` option.
| -rw-r--r-- | parse.y | 32 | ||||
| -rw-r--r-- | prism/config.yml | 2 | ||||
| -rw-r--r-- | prism/prism.c | 69 | ||||
| -rw-r--r-- | prism/templates/src/diagnostic.c.erb | 2 | ||||
| -rw-r--r-- | spec/ruby/language/pattern_matching_spec.rb | 2 | ||||
| -rw-r--r-- | test/prism/result/source_location_test.rb | 2 | ||||
| -rw-r--r-- | test/ruby/test_pattern_matching.rb | 19 |
7 files changed, 95 insertions, 33 deletions
@@ -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 |
