summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortompng <[email protected]>2024-12-13 02:19:58 +0900
committerNobuyoshi Nakada <[email protected]>2024-12-15 16:55:30 +0900
commite06b3b5ad1f6453ebebc5d9a54d82e3bb2ab116f (patch)
tree18e7517576f95fd16ffbf1858707a7bc4aa11c1a
parent730731cc86d1cf87a3478ffc242d52c70eda2e42 (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.c42
-rw-r--r--test/ruby/test_parse.rb21
2 files changed, 44 insertions, 19 deletions
diff --git a/compile.c b/compile.c
index 66bc9d63b8..3f894cbe69 100644
--- a/compile.c
+++ b/compile.c
@@ -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;'}")