summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorS-H-GAMELINKS <gamelinks007@gmail.com>2025-07-21 11:00:33 +0900
committerKevin Newton <kddnewton@gmail.com>2025-08-05 13:58:09 -0400
commitb482e3d7cd77c688ed0e38e1c95c1f0b2b205cd6 (patch)
tree767ba8c44c2efe160096500e5c1d9b3e27d6dc8d
parent6e2b139d6ac1bcbae26c06a4e3022e8b2be8307e (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.c9
-rw-r--r--test/prism/fixtures/it_assignment.txt1
-rw-r--r--test/prism/ruby/parser_test.rb19
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(&current_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(&current_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)