diff options
-rw-r--r-- | compile.c | 33 | ||||
-rw-r--r-- | test/ruby/test_literal.rb | 17 |
2 files changed, 42 insertions, 8 deletions
@@ -3847,7 +3847,7 @@ enum compile_array_type_t { }; static inline int -static_literal_node_p(const NODE *node) +static_literal_node_p(const NODE *node, const rb_iseq_t *iseq) { node = node->nd_head; switch (nd_type(node)) { @@ -3856,13 +3856,19 @@ static_literal_node_p(const NODE *node) case NODE_TRUE: case NODE_FALSE: return TRUE; + case NODE_STR: + if (ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal) { + return TRUE; + } else { + return FALSE; + } default: return FALSE; } } static inline VALUE -static_literal_value(const NODE *node) +static_literal_value(const NODE *node, rb_iseq_t *iseq) { node = node->nd_head; switch (nd_type(node)) { @@ -3872,6 +3878,17 @@ static_literal_value(const NODE *node) return Qtrue; case NODE_FALSE: return Qfalse; + case NODE_STR: + if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) { + VALUE lit; + VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX((int)nd_line(node))); + lit = rb_str_dup(node->nd_lit); + rb_ivar_set(lit, id_debug_created_info, rb_obj_freeze(debug_info)); + return rb_str_freeze(lit); + } + else { + return rb_fstring(node->nd_lit); + } default: return node->nd_lit; } @@ -3921,7 +3938,7 @@ compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node_ro } break; } - if (opt_p && !static_literal_node_p(node)) { + if (opt_p && !static_literal_node_p(node, iseq)) { opt_p = 0; } @@ -3943,15 +3960,15 @@ compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node_ro node = start_node; while (node != end_node) { - rb_ary_push(ary, static_literal_value(node)); + rb_ary_push(ary, static_literal_value(node, iseq)); node = node->nd_next; } while (node && node->nd_next && - static_literal_node_p(node) && - static_literal_node_p(node->nd_next)) { + static_literal_node_p(node, iseq) && + static_literal_node_p(node->nd_next, iseq)) { VALUE elem[2]; - elem[0] = static_literal_value(node); - elem[1] = static_literal_value(node->nd_next); + elem[0] = static_literal_value(node, iseq); + elem[1] = static_literal_value(node->nd_next, iseq); rb_ary_cat(ary, elem, 2); node = node->nd_next->nd_next; len++; diff --git a/test/ruby/test_literal.rb b/test/ruby/test_literal.rb index 3b6aa0c096..178cc83fa3 100644 --- a/test/ruby/test_literal.rb +++ b/test/ruby/test_literal.rb @@ -177,6 +177,12 @@ class TestRubyLiteral < Test::Unit::TestCase end end + def test_frozen_string_in_array_literal + list = eval("# frozen-string-literal: true\n""['foo', 'bar']") + assert_equal 2, list.length + list.each { |str| assert_predicate str, :frozen? } + end + if defined?(RubyVM::InstructionSequence.compile_option) and RubyVM::InstructionSequence.compile_option.key?(:debug_frozen_string_literal) def test_debug_frozen_string @@ -189,6 +195,17 @@ class TestRubyLiteral < Test::Unit::TestCase str << "x" } end + + def test_debug_frozen_string_in_array_literal + src = '["foo"]'; f = "test.rb"; n = 1 + opt = {frozen_string_literal: true, debug_frozen_string_literal: true} + ary = RubyVM::InstructionSequence.compile(src, f, f, n, opt).eval + assert_equal("foo", ary.first) + assert_predicate(ary.first, :frozen?) + assert_raise_with_message(FrozenError, /created at #{Regexp.quote(f)}:#{n}/) { + ary.first << "x" + } + end end def test_regexp |