From 0667d23f4f083ca56906a2f1695a60bf4779618a Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Thu, 26 Mar 2026 19:08:45 +0100 Subject: [PATCH] Fix `Source.offsets` with `freeze: true` We still need to do it eagerly when the result will be frozen, same as for locations. Fixes the following error for the added test: > FrozenError: can't modify frozen Prism::ASCIISource: # --- templates/ext/prism/api_node.c.erb | 9 ++++++++- test/prism/api/freeze_test.rb | 5 +++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/templates/ext/prism/api_node.c.erb b/templates/ext/prism/api_node.c.erb index 71f7fe273e..41d7165930 100644 --- a/templates/ext/prism/api_node.c.erb +++ b/templates/ext/prism/api_node.c.erb @@ -82,11 +82,18 @@ pm_source_new(const pm_parser_t *parser, rb_encoding *encoding, bool freeze) { VALUE source_string = rb_enc_str_new((const char *) start, pm_parser_end(parser) - start, encoding); const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser); - VALUE offsets = rb_str_new((const char *) line_offsets->offsets, line_offsets->size * sizeof(uint32_t)); + VALUE offsets; if (freeze) { + offsets = rb_ary_new_capa(line_offsets->size); + for (size_t index = 0; index < line_offsets->size; index++) { + rb_ary_push(offsets, ULONG2NUM(line_offsets->offsets[index])); + } + rb_obj_freeze(source_string); rb_obj_freeze(offsets); + } else { + offsets = rb_str_new((const char *) line_offsets->offsets, line_offsets->size * sizeof(uint32_t)); } VALUE source = rb_funcall(rb_cPrismSource, rb_intern("for"), 3, source_string, LONG2NUM(pm_parser_start_line(parser)), offsets); diff --git a/test/prism/api/freeze_test.rb b/test/prism/api/freeze_test.rb index 5533a00331..bf91792e69 100644 --- a/test/prism/api/freeze_test.rb +++ b/test/prism/api/freeze_test.rb @@ -8,6 +8,11 @@ def test_parse assert_frozen(Prism.parse("1 + 2; %i{foo} + %i{bar}", freeze: true)) end + def test_offsets_usable + node = Prism.parse_statement("1 + 2", freeze: true) + assert_equal(1, node.start_line) + end + def test_lex assert_frozen(Prism.lex("1 + 2; %i{foo} + %i{bar}", freeze: true)) end