diff options
author | tompng <[email protected]> | 2024-12-13 02:19:58 +0900 |
---|---|---|
committer | Nobuyoshi Nakada <[email protected]> | 2024-12-15 16:55:30 +0900 |
commit | e06b3b5ad1f6453ebebc5d9a54d82e3bb2ab116f (patch) | |
tree | 18e7517576f95fd16ffbf1858707a7bc4aa11c1a | |
parent | 730731cc86d1cf87a3478ffc242d52c70eda2e42 (diff) |
[Bug #20927] Fix compile_shareable_literal_constant for hash with keyword splat
Compilation of NODE_HASH in compile_shareable_literal_constant does not support hash that contains keyword splat.
If there is a keyword splat, fallback to default case.
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/12338
-rw-r--r-- | compile.c | 42 | ||||
-rw-r--r-- | test/ruby/test_parse.rb | 21 |
2 files changed, 44 insertions, 19 deletions
@@ -10473,6 +10473,12 @@ compile_shareable_literal_constant(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_pa *shareable_literal_p = 0; return COMPILE_OK; } + for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) { + if (!RNODE_LIST(n)->nd_head) { + // If the hash node have a keyword splat, fall back to the default case. + goto compile_shareable; + } + } INIT_ANCHOR(anchor); lit = rb_hash_new(); @@ -10482,25 +10488,21 @@ compile_shareable_literal_constant(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_pa int shareable_literal_p2; NODE *key = RNODE_LIST(n)->nd_head; NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head; - if (key) { - CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2)); - if (shareable_literal_p2) { - /* noop */ - } - else if (RTEST(lit)) { - rb_hash_clear(lit); - lit = Qfalse; - } + CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2)); + if (shareable_literal_p2) { + /* noop */ } - if (val) { - CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2)); - if (shareable_literal_p2) { - /* noop */ - } - else if (RTEST(lit)) { - rb_hash_clear(lit); - lit = Qfalse; - } + else if (RTEST(lit)) { + rb_hash_clear(lit); + lit = Qfalse; + } + CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2)); + if (shareable_literal_p2) { + /* noop */ + } + else if (RTEST(lit)) { + rb_hash_clear(lit); + lit = Qfalse; } if (RTEST(lit)) { if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) { @@ -10516,6 +10518,8 @@ compile_shareable_literal_constant(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_pa } default: + + compile_shareable: if (shareable == rb_parser_shareable_literal && (SHAREABLE_BARE_EXPRESSION || level > 0)) { CHECK(compile_ensure_shareable_node(iseq, ret, dest, node)); @@ -10529,7 +10533,7 @@ compile_shareable_literal_constant(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_pa return COMPILE_OK; } - /* Array or Hash */ + /* Array or Hash that does not have keyword splat */ if (!lit) { if (nd_type(node) == NODE_LIST) { ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen)); diff --git a/test/ruby/test_parse.rb b/test/ruby/test_parse.rb index d52e480eb9..0ed4dd84e7 100644 --- a/test/ruby/test_parse.rb +++ b/test/ruby/test_parse.rb @@ -2,6 +2,7 @@ # frozen_string_literal: false require 'test/unit' require 'stringio' +require_relative '../lib/parser_support' class TestParse < Test::Unit::TestCase def setup @@ -1609,6 +1610,26 @@ x = __ENCODING__ assert_ractor_shareable(a[0]) end + def test_shareable_constant_value_hash_with_keyword_splat + # Prism compiler does not support keyword splat in Ractor constant [Bug #20916] + omit if ParserSupport.prism_enabled? + + a, b = eval_separately("#{<<~"begin;"}\n#{<<~'end;'}") + begin; + # shareable_constant_value: experimental_everything + # [Bug #20927] + x = { x: {} } + y = { y: {} } + A = { **x } + B = { x: {}, **y } + [A, B] + end; + assert_ractor_shareable(a) + assert_ractor_shareable(b) + assert_equal({ x: {}}, a) + assert_equal({ x: {}, y: {}}, b) + end + def test_shareable_constant_value_unshareable_literal assert_raise_separately(Ractor::IsolationError, /unshareable object to C/, "#{<<~"begin;"}\n#{<<~'end;'}") |