From ea91ab696e6ee7225a2dde909e60dd9d0b241935 Mon Sep 17 00:00:00 2001 From: yui-knk Date: Sat, 6 Jan 2024 17:33:20 +0900 Subject: [PATCH] Fix constant name of `Ractor::IsolationError` message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `dest` of `const_decl_path` is `NODE_COLON2` or `NODE_COLON3` in some cases. For example, `B::C ||= [“Not ” + “shareable”]` passes `NODE_COLON2` and `::C ||= [“Not ” + “shareable”]` passes `NODE_COLON3`. This commit fixes `Ractor::IsolationError` message for such case. ``` # shareable_constant_value: literal ::C ||= ["Not " + "shareable"] # Before # => cannot assign unshareable object to C (Ractor::IsolationError) # After # => cannot assign unshareable object to ::C (Ractor::IsolationError) ``` --- ruby_parser.c | 43 +++++++++++++++++++++++++++++------------ test/ruby/test_parse.rb | 34 ++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 12 deletions(-) diff --git a/ruby_parser.c b/ruby_parser.c index c48f563744..7061f2be5b 100644 --- a/ruby_parser.c +++ b/ruby_parser.c @@ -1045,22 +1045,40 @@ VALUE rb_node_const_decl_val(const NODE *node) { VALUE path; - if (RNODE_CDECL(node)->nd_vid) { - path = rb_id2str(RNODE_CDECL(node)->nd_vid); + switch (nd_type(node)) { + case NODE_CDECL: + if (RNODE_CDECL(node)->nd_vid) { + path = rb_id2str(RNODE_CDECL(node)->nd_vid); + goto end; + } + else { + node = RNODE_CDECL(node)->nd_else; + } + break; + case NODE_COLON2: + break; + case NODE_COLON3: + // ::Const + path = rb_str_new_cstr("::"); + rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid)); + goto end; + default: + rb_bug("unexpected node: %s", ruby_node_name(nd_type(node))); + UNREACHABLE_RETURN(0); } - else { - NODE *n = RNODE_CDECL(node)->nd_else; - path = rb_ary_new(); - for (; n && nd_type_p(n, NODE_COLON2); n = RNODE_COLON2(n)->nd_head) { - rb_ary_push(path, rb_id2str(RNODE_COLON2(n)->nd_mid)); + + path = rb_ary_new(); + if (node) { + for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) { + rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid)); } - if (n && nd_type_p(n, NODE_CONST)) { + if (node && nd_type_p(node, NODE_CONST)) { // Const::Name - rb_ary_push(path, rb_id2str(RNODE_CONST(n)->nd_vid)); + rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid)); } - else if (n && nd_type_p(n, NODE_COLON3)) { + else if (node && nd_type_p(node, NODE_COLON3)) { // ::Const::Name - rb_ary_push(path, rb_id2str(RNODE_COLON3(n)->nd_mid)); + rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid)); rb_ary_push(path, rb_str_new(0, 0)); } else { @@ -1068,7 +1086,8 @@ rb_node_const_decl_val(const NODE *node) rb_ary_push(path, rb_str_new_cstr("...")); } path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::")); - path = rb_fstring(path); } + end: + path = rb_fstring(path); return path; } diff --git a/test/ruby/test_parse.rb b/test/ruby/test_parse.rb index b6d306352c..edf61db325 100644 --- a/test/ruby/test_parse.rb +++ b/test/ruby/test_parse.rb @@ -1568,6 +1568,40 @@ x = __ENCODING__ ::B::C = ["Not " + "shareable"] end end; + + assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") + begin; + assert_raise_with_message(Ractor::IsolationError, /unshareable object to ::C/) do + # shareable_constant_value: literal + ::C ||= ["Not " + "shareable"] + end + end; + + assert_raise_separately(Ractor::IsolationError, /unshareable object to B::C/, + "#{<<~"begin;"}\n#{<<~'end;'}") + begin; + # shareable_constant_value: literal + B = Class.new + B::C ||= ["Not " + "shareable"] + end; + + assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") + begin; + assert_raise_with_message(Ractor::IsolationError, /unshareable object to ::B::C/) do + # shareable_constant_value: literal + ::B = Class.new + ::B::C ||= ["Not " + "shareable"] + end + end; + + assert_raise_separately(Ractor::IsolationError, /unshareable object to ...::C/, + "#{<<~"begin;"}\n#{<<~'end;'}") + begin; + # shareable_constant_value: literal + B = Class.new + def self.expr; B; end + expr::C ||= ["Not " + "shareable"] + end; end def test_shareable_constant_value_nonliteral