diff options
| author | S-H-GAMELINKS <gamelinks007@gmail.com> | 2025-07-21 11:00:33 +0900 |
|---|---|---|
| committer | Kevin Newton <kddnewton@gmail.com> | 2025-08-05 13:58:09 -0400 |
| commit | b482e3d7cd77c688ed0e38e1c95c1f0b2b205cd6 (patch) | |
| tree | 767ba8c44c2efe160096500e5c1d9b3e27d6dc8d | |
| parent | 6e2b139d6ac1bcbae26c06a4e3022e8b2be8307e (diff) | |
[ruby/prism] Make `it = it` assign `nil` to match parse.y behavior [Bug #21139]
Currently Prism returns `42` for code like this:
```ruby
42.tap { it = it; p it } # => 42
```
But parse.y returns `nil`:
```ruby
42.tap { it = it; p it } # => nil
```
In parse.y, it on the right-hand side is parsed as a local variable.
In Prism, it was parsed as the implicit block parameter it, which caused this inconsistent behavior.
This change makes the right-hand side it to be parsed as a local variable, aligning with parse.y's behavior.
Bug ticket: https://bugs.ruby-lang.org/issues/21139
https://github.com/ruby/prism/commit/cf3bbf9d2c
| -rw-r--r-- | prism/prism.c | 9 | ||||
| -rw-r--r-- | test/prism/fixtures/it_assignment.txt | 1 | ||||
| -rw-r--r-- | test/prism/ruby/parser_test.rb | 19 |
3 files changed, 28 insertions, 1 deletions
diff --git a/prism/prism.c b/prism/prism.c index 4d2c372d5d..85098c52d8 100644 --- a/prism/prism.c +++ b/prism/prism.c @@ -16459,7 +16459,14 @@ parse_variable(pm_parser_t *parser) { pm_node_list_append(¤t_scope->implicit_parameters, node); return node; - } else if ((parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) && pm_token_is_it(parser->previous.start, parser->previous.end)) { + } else if ((parser->version != PM_OPTIONS_VERSION_CRUBY_3_3) && pm_token_is_it(parser->previous.start, parser->previous.end)) { + if (match1(parser, PM_TOKEN_EQUAL)) { + pm_constant_id_t name_id = pm_parser_local_add_location(parser, parser->previous.start, parser->previous.end, 0); + pm_node_t *node = (pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, 0, false); + + return node; + } + pm_node_t *node = (pm_node_t *) pm_it_local_variable_read_node_create(parser, &parser->previous); pm_node_list_append(¤t_scope->implicit_parameters, node); diff --git a/test/prism/fixtures/it_assignment.txt b/test/prism/fixtures/it_assignment.txt new file mode 100644 index 0000000000..523b0ffe1e --- /dev/null +++ b/test/prism/fixtures/it_assignment.txt @@ -0,0 +1 @@ +42.tap { it = it; p it } diff --git a/test/prism/ruby/parser_test.rb b/test/prism/ruby/parser_test.rb index 156e8f9e9f..7bf2e59a86 100644 --- a/test/prism/ruby/parser_test.rb +++ b/test/prism/ruby/parser_test.rb @@ -183,6 +183,25 @@ module Prism assert_equal(it_block_parameter_sexp, actual_ast.to_sexp) end + def test_it_assignment_syntax + it_assignment_fixture_path = Pathname(__dir__).join('../../../test/prism/fixtures/it_assignment.txt') + + buffer = Parser::Source::Buffer.new(it_assignment_fixture_path) + buffer.source = it_assignment_fixture_path.read + actual_ast = Prism::Translation::Parser34.new.tokenize(buffer)[0] + + it_assignment_sexp = parse_sexp { + s(:block, + s(:send, s(:int, 42), :tap), + s(:args), + s(:begin, + s(:lvasgn, :it, s(:lvar, :it)), + s(:send, nil, :p, s(:lvar, :it)))) + } + + assert_equal(it_assignment_sexp, actual_ast.to_sexp) + end + private def assert_equal_parses(fixture, compare_asts: true, compare_tokens: true, compare_comments: true) |
