[ruby-core:121389] [Ruby Bug#21187] Strings concatenated with `\` getting frozen with literal hashes (PRISM only)

Issue #21187 has been reported by LocoDelAssembly (Hernán Pereira). ---------------------------------------- Bug #21187: Strings concatenated with `\` getting frozen with literal hashes (PRISM only) https://bugs.ruby-lang.org/issues/21187 * Author: LocoDelAssembly (Hernán Pereira) * Status: Open * ruby -v: ruby 3.4.2 (2025-02-15 revision d2930f8e7a) +PRISM [x86_64-linux] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- When the first elements of a literal hash are strings that are concatenated with `\`, those elements are flagged with `PM_NODE_FLAG_STATIC_LITERAL` and a special optimization that I believe was introduced in https://github.com/ruby/ruby/commit/8080de04be8e99e71309745822a9d436cc4ae37c causes the strings to be frozen. Reproduction === test.rb ``` a = { a: 'one' \ 'two', b: 'three' \ 'four', c: 'five', d: 'six' \ 'seven' } b = { a: 'one', b: 'two' \ 'three' } puts "a = #{a.map { |k,v| {k => v.frozen?} }}" puts "b = #{b.map { |k,v| {k => v.frozen?} }}" ``` With prism: ``` $ ruby test.rb a = [{a: true}, {b: true}, {c: false}, {d: false}] b = [{a: false}, {b: false}] ``` With parse.y: ``` $ ruby --parser=parse.y test.rb a = [{a: false}, {b: false}, {c: false}, {d: false}] b = [{a: false}, {b: false}] ``` (Notice `b` hash is unaffected in both parsers) Not sure if this is just part of undefined behavior or this is indeed a bug. Assigning a string concatenated with `\` to a variable doesn't make it frozen, to the best of my knowledge this seems to be hash-specific. -- https://bugs.ruby-lang.org/

Issue #21187 has been updated by alanwu (Alan Wu). Assignee set to prism ---------------------------------------- Bug #21187: Strings concatenated with `\` getting frozen with literal hashes (PRISM only) https://bugs.ruby-lang.org/issues/21187#change-112709 * Author: LocoDelAssembly (Hernán Pereira) * Status: Open * Assignee: prism * ruby -v: ruby 3.4.2 (2025-02-15 revision d2930f8e7a) +PRISM [x86_64-linux] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- When the first elements of a literal hash are strings that are concatenated with `\`, those elements are flagged with `PM_NODE_FLAG_STATIC_LITERAL` and a special optimization that I believe was introduced in https://github.com/ruby/ruby/commit/8080de04be8e99e71309745822a9d436cc4ae37c causes the strings to be frozen. Reproduction === test.rb ``` a = { a: 'one' \ 'two', b: 'three' \ 'four', c: 'five', d: 'six' \ 'seven' } b = { a: 'one', b: 'two' \ 'three' } puts "a = #{a.map { |k,v| {k => v.frozen?} }}" puts "b = #{b.map { |k,v| {k => v.frozen?} }}" ``` With prism: ``` $ ruby test.rb a = [{a: true}, {b: true}, {c: false}, {d: false}] b = [{a: false}, {b: false}] ``` With parse.y: ``` $ ruby --parser=parse.y test.rb a = [{a: false}, {b: false}, {c: false}, {d: false}] b = [{a: false}, {b: false}] ``` (Notice `b` hash is unaffected in both parsers) Not sure if this is just part of undefined behavior or this is indeed a bug. Assigning a string concatenated with `\` to a variable doesn't make it frozen, to the best of my knowledge this seems to be hash-specific. -- https://bugs.ruby-lang.org/

Issue #21187 has been updated by kddnewton (Kevin Newton). Status changed from Closed to Open I think this might not be fixed. I'm reopening to keep investigating. ---------------------------------------- Bug #21187: Strings concatenated with `\` getting frozen with literal hashes (PRISM only) https://bugs.ruby-lang.org/issues/21187#change-114574 * Author: LocoDelAssembly (Hernán Pereira) * Status: Open * Assignee: prism * ruby -v: ruby 3.4.2 (2025-02-15 revision d2930f8e7a) +PRISM [x86_64-linux] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- When the first elements of a literal hash are strings that are concatenated with `\`, those elements are flagged with `PM_NODE_FLAG_STATIC_LITERAL` and a special optimization that I believe was introduced in https://github.com/ruby/ruby/commit/8080de04be8e99e71309745822a9d436cc4ae37c causes the strings to be frozen. Reproduction === test.rb ``` a = { a: 'one' \ 'two', b: 'three' \ 'four', c: 'five', d: 'six' \ 'seven' } b = { a: 'one', b: 'two' \ 'three' } puts "a = #{a.map { |k,v| {k => v.frozen?} }}" puts "b = #{b.map { |k,v| {k => v.frozen?} }}" ``` With prism: ``` $ ruby test.rb a = [{a: true}, {b: true}, {c: false}, {d: false}] b = [{a: false}, {b: false}] ``` With parse.y: ``` $ ruby --parser=parse.y test.rb a = [{a: false}, {b: false}, {c: false}, {d: false}] b = [{a: false}, {b: false}] ``` (Notice `b` hash is unaffected in both parsers) Not sure if this is just part of undefined behavior or this is indeed a bug. Assigning a string concatenated with `\` to a variable doesn't make it frozen, to the best of my knowledge this seems to be hash-specific. -- https://bugs.ruby-lang.org/

Issue #21187 has been updated by tenderlovemaking (Aaron Patterson). @kddnewton any updates, or reproduction issues? I'm confident I fixed the issue OP reported. ---------------------------------------- Bug #21187: Strings concatenated with `\` getting frozen with literal hashes (PRISM only) https://bugs.ruby-lang.org/issues/21187#change-114722 * Author: LocoDelAssembly (Hernán Pereira) * Status: Open * Assignee: prism * ruby -v: ruby 3.4.2 (2025-02-15 revision d2930f8e7a) +PRISM [x86_64-linux] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- When the first elements of a literal hash are strings that are concatenated with `\`, those elements are flagged with `PM_NODE_FLAG_STATIC_LITERAL` and a special optimization that I believe was introduced in https://github.com/ruby/ruby/commit/8080de04be8e99e71309745822a9d436cc4ae37c causes the strings to be frozen. Reproduction === test.rb ``` a = { a: 'one' \ 'two', b: 'three' \ 'four', c: 'five', d: 'six' \ 'seven' } b = { a: 'one', b: 'two' \ 'three' } puts "a = #{a.map { |k,v| {k => v.frozen?} }}" puts "b = #{b.map { |k,v| {k => v.frozen?} }}" ``` With prism: ``` $ ruby test.rb a = [{a: true}, {b: true}, {c: false}, {d: false}] b = [{a: false}, {b: false}] ``` With parse.y: ``` $ ruby --parser=parse.y test.rb a = [{a: false}, {b: false}, {c: false}, {d: false}] b = [{a: false}, {b: false}] ``` (Notice `b` hash is unaffected in both parsers) Not sure if this is just part of undefined behavior or this is indeed a bug. Assigning a string concatenated with `\` to a variable doesn't make it frozen, to the best of my knowledge this seems to be hash-specific. -- https://bugs.ruby-lang.org/

Issue #21187 has been updated by kddnewton (Kevin Newton). Yeah, it broke CI on macOS https://github.com/ruby/ruby/actions/runs/16430139182/job/46429723627#step:9... ---------------------------------------- Bug #21187: Strings concatenated with `\` getting frozen with literal hashes (PRISM only) https://bugs.ruby-lang.org/issues/21187#change-114724 * Author: LocoDelAssembly (Hernán Pereira) * Status: Open * Assignee: prism * ruby -v: ruby 3.4.2 (2025-02-15 revision d2930f8e7a) +PRISM [x86_64-linux] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- When the first elements of a literal hash are strings that are concatenated with `\`, those elements are flagged with `PM_NODE_FLAG_STATIC_LITERAL` and a special optimization that I believe was introduced in https://github.com/ruby/ruby/commit/8080de04be8e99e71309745822a9d436cc4ae37c causes the strings to be frozen. Reproduction === test.rb ``` a = { a: 'one' \ 'two', b: 'three' \ 'four', c: 'five', d: 'six' \ 'seven' } b = { a: 'one', b: 'two' \ 'three' } puts "a = #{a.map { |k,v| {k => v.frozen?} }}" puts "b = #{b.map { |k,v| {k => v.frozen?} }}" ``` With prism: ``` $ ruby test.rb a = [{a: true}, {b: true}, {c: false}, {d: false}] b = [{a: false}, {b: false}] ``` With parse.y: ``` $ ruby --parser=parse.y test.rb a = [{a: false}, {b: false}, {c: false}, {d: false}] b = [{a: false}, {b: false}] ``` (Notice `b` hash is unaffected in both parsers) Not sure if this is just part of undefined behavior or this is indeed a bug. Assigning a string concatenated with `\` to a variable doesn't make it frozen, to the best of my knowledge this seems to be hash-specific. -- https://bugs.ruby-lang.org/

Issue #21187 has been updated by Earlopain (Earlopain _). So this was partially reverted via https://github.com/ruby/ruby/commit/7dbd9c26361719a45fa39838f46a76d67dc3c2e9. It reverts the ruby/prism changes but kept the compiler changes from https://github.com/ruby/ruby/pull/13966. I think the macos issue might have stemmed from the fact that all flags were cleared. That includes the one from `frozen_string_literal: false` which `rbconfig.rb` has. Seems like something that could cause this, and indeed the mutable flag got cleared from `"foo""bar"` which `rbconfig.rb` contains on macos You added a test that `"'a' 'b'"` should not have `PM_NODE_FLAG_STATIC_LITERAL` but that doesn't look correct to me? At least from the description about that flag from the docs (A flag to indicate that the value that the node represents is a value that can be determined at parse-time). It does not mean frozen is my understanding. I feel like the prism side is already correct, just some compiler optimization is missing some extra condition somewhere to not apply. `"'a' 'b'"` is static, `"a" "b#{c}"` is not, which is my understanding of how it should be behave. (For some reason I thought the compiler changes were enough by themselves but I tested now on 3.4.6 and master, and the behaviour OP describes is still present). So, indeed not fixed. ---------------------------------------- Bug #21187: Strings concatenated with `\` getting frozen with literal hashes (PRISM only) https://bugs.ruby-lang.org/issues/21187#change-114729 * Author: LocoDelAssembly (Hernán Pereira) * Status: Open * Assignee: prism * ruby -v: ruby 3.4.2 (2025-02-15 revision d2930f8e7a) +PRISM [x86_64-linux] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- When the first elements of a literal hash are strings that are concatenated with `\`, those elements are flagged with `PM_NODE_FLAG_STATIC_LITERAL` and a special optimization that I believe was introduced in https://github.com/ruby/ruby/commit/8080de04be8e99e71309745822a9d436cc4ae37c causes the strings to be frozen. Reproduction === test.rb ``` a = { a: 'one' \ 'two', b: 'three' \ 'four', c: 'five', d: 'six' \ 'seven' } b = { a: 'one', b: 'two' \ 'three' } puts "a = #{a.map { |k,v| {k => v.frozen?} }}" puts "b = #{b.map { |k,v| {k => v.frozen?} }}" ``` With prism: ``` $ ruby test.rb a = [{a: true}, {b: true}, {c: false}, {d: false}] b = [{a: false}, {b: false}] ``` With parse.y: ``` $ ruby --parser=parse.y test.rb a = [{a: false}, {b: false}, {c: false}, {d: false}] b = [{a: false}, {b: false}] ``` (Notice `b` hash is unaffected in both parsers) Not sure if this is just part of undefined behavior or this is indeed a bug. Assigning a string concatenated with `\` to a variable doesn't make it frozen, to the best of my knowledge this seems to be hash-specific. -- https://bugs.ruby-lang.org/

Issue #21187 has been updated by Earlopain (Earlopain _). Turns out the prism commit was reverted before the compiler change was merged. Then the ruby/ruby PR was merged, which contained the reverted code again, essentially fixing this issue. Then https://github.com/ruby/ruby/commit/e74524616013c616744ebf8168f1ad57eee74a05 came along and "broke" it again, since it gave the impression of being reverted during 3.4.6 release. A bit of a mess to be honest. I did notice an issue with the original approach where these concatinated strings no longer warn about chilled strings. It has to preserve frozen-ness/mutability when concatinating string literals like `"foo""bar"`. I have https://github.com/ruby/prism/pull/3667 for the prism side and https://github.com/ruby/ruby/pull/14697 for the compiler. ---------------------------------------- Bug #21187: Strings concatenated with `\` getting frozen with literal hashes (PRISM only) https://bugs.ruby-lang.org/issues/21187#change-114732 * Author: LocoDelAssembly (Hernán Pereira) * Status: Open * Assignee: prism * ruby -v: ruby 3.4.2 (2025-02-15 revision d2930f8e7a) +PRISM [x86_64-linux] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- When the first elements of a literal hash are strings that are concatenated with `\`, those elements are flagged with `PM_NODE_FLAG_STATIC_LITERAL` and a special optimization that I believe was introduced in https://github.com/ruby/ruby/commit/8080de04be8e99e71309745822a9d436cc4ae37c causes the strings to be frozen. Reproduction === test.rb ``` a = { a: 'one' \ 'two', b: 'three' \ 'four', c: 'five', d: 'six' \ 'seven' } b = { a: 'one', b: 'two' \ 'three' } puts "a = #{a.map { |k,v| {k => v.frozen?} }}" puts "b = #{b.map { |k,v| {k => v.frozen?} }}" ``` With prism: ``` $ ruby test.rb a = [{a: true}, {b: true}, {c: false}, {d: false}] b = [{a: false}, {b: false}] ``` With parse.y: ``` $ ruby --parser=parse.y test.rb a = [{a: false}, {b: false}, {c: false}, {d: false}] b = [{a: false}, {b: false}] ``` (Notice `b` hash is unaffected in both parsers) Not sure if this is just part of undefined behavior or this is indeed a bug. Assigning a string concatenated with `\` to a variable doesn't make it frozen, to the best of my knowledge this seems to be hash-specific. -- https://bugs.ruby-lang.org/

Issue #21187 has been updated by k0kubun (Takashi Kokubun).
Turns out the prism commit was reverted before the compiler change was merged. A bit of a mess to be honest.
I think the maintainers understand this, but the thing is * A Prism change that needs a compiler fix should be merged to ruby/ruby first, and then reverse-synced to ruby/prism. * When you merge such a change to ruby/prism first and it breaks ruby/ruby CI, the change will be reverted, at least on the ruby/ruby side. This started the out-of-sync situation. * If you don't want this to happen, you probably want to have `prism_compile.{c,h}` in ruby/prism as well. `cruby-bindings.yml` would test it, so it's not impossible. * When something is changed on ruby/ruby master (in this case, a sync from ruby/prism was reverted), it should be reverse-synced to ruby/prism as soon as possible. * There's nothing that prevents you from leaving the out-of-sync ruby/prism at the moment. This time, they were out of sync for a while without anybody noticing it. * Perhaps `cruby-bindings.yml` should fail at the `tool/sync_default_gems.rb` step when there's a diff not made by the Prism PR itself. It should let you notice ruby/prism is out of sync (due to a revert in ruby/ruby, for example) when it fails there. There's no point in running the CRuby test when it's not going to be the ruby/ruby code after merging the ruby/prism PR. ---------------------------------------- Bug #21187: Strings concatenated with `\` getting frozen with literal hashes (PRISM only) https://bugs.ruby-lang.org/issues/21187#change-114734 * Author: LocoDelAssembly (Hernán Pereira) * Status: Closed * Assignee: prism * ruby -v: ruby 3.4.2 (2025-02-15 revision d2930f8e7a) +PRISM [x86_64-linux] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- When the first elements of a literal hash are strings that are concatenated with `\`, those elements are flagged with `PM_NODE_FLAG_STATIC_LITERAL` and a special optimization that I believe was introduced in https://github.com/ruby/ruby/commit/8080de04be8e99e71309745822a9d436cc4ae37c causes the strings to be frozen. Reproduction === test.rb ``` a = { a: 'one' \ 'two', b: 'three' \ 'four', c: 'five', d: 'six' \ 'seven' } b = { a: 'one', b: 'two' \ 'three' } puts "a = #{a.map { |k,v| {k => v.frozen?} }}" puts "b = #{b.map { |k,v| {k => v.frozen?} }}" ``` With prism: ``` $ ruby test.rb a = [{a: true}, {b: true}, {c: false}, {d: false}] b = [{a: false}, {b: false}] ``` With parse.y: ``` $ ruby --parser=parse.y test.rb a = [{a: false}, {b: false}, {c: false}, {d: false}] b = [{a: false}, {b: false}] ``` (Notice `b` hash is unaffected in both parsers) Not sure if this is just part of undefined behavior or this is indeed a bug. Assigning a string concatenated with `\` to a variable doesn't make it frozen, to the best of my knowledge this seems to be hash-specific. -- https://bugs.ruby-lang.org/

Issue #21187 has been updated by Earlopain (Earlopain _). It was my bad, I did not look at the history and only noticed what happened in what order now. From what I gathered someone was notified of the revert. Thank you for taking the time to explain the process in such detail. I was uncertain what should happen in which order. ruby/ruby first and clean up after makes sense to me. ---------------------------------------- Bug #21187: Strings concatenated with `\` getting frozen with literal hashes (PRISM only) https://bugs.ruby-lang.org/issues/21187#change-114736 * Author: LocoDelAssembly (Hernán Pereira) * Status: Closed * Assignee: prism * ruby -v: ruby 3.4.2 (2025-02-15 revision d2930f8e7a) +PRISM [x86_64-linux] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- When the first elements of a literal hash are strings that are concatenated with `\`, those elements are flagged with `PM_NODE_FLAG_STATIC_LITERAL` and a special optimization that I believe was introduced in https://github.com/ruby/ruby/commit/8080de04be8e99e71309745822a9d436cc4ae37c causes the strings to be frozen. Reproduction === test.rb ``` a = { a: 'one' \ 'two', b: 'three' \ 'four', c: 'five', d: 'six' \ 'seven' } b = { a: 'one', b: 'two' \ 'three' } puts "a = #{a.map { |k,v| {k => v.frozen?} }}" puts "b = #{b.map { |k,v| {k => v.frozen?} }}" ``` With prism: ``` $ ruby test.rb a = [{a: true}, {b: true}, {c: false}, {d: false}] b = [{a: false}, {b: false}] ``` With parse.y: ``` $ ruby --parser=parse.y test.rb a = [{a: false}, {b: false}, {c: false}, {d: false}] b = [{a: false}, {b: false}] ``` (Notice `b` hash is unaffected in both parsers) Not sure if this is just part of undefined behavior or this is indeed a bug. Assigning a string concatenated with `\` to a variable doesn't make it frozen, to the best of my knowledge this seems to be hash-specific. -- https://bugs.ruby-lang.org/
participants (6)
-
alanwu (Alan Wu)
-
Earlopain (Earlopain _)
-
k0kubun (Takashi Kokubun)
-
kddnewton (Kevin Newton)
-
LocoDelAssembly
-
tenderlovemaking (Aaron Patterson)