зеркало из https://github.com/github/ruby.git
Interpolated strings are no longer frozen with frozen-string-literal: true
* Remove freezestring instruction since this was the only usage for it. * [Feature #17104]
This commit is contained in:
Родитель
fbba6bd4e3
Коммит
9b535f3ff7
4
NEWS.md
4
NEWS.md
|
@ -80,6 +80,9 @@ sufficient information, see the ChangeLog file or Redmine
|
|||
def square(x) = x * x
|
||||
```
|
||||
|
||||
* Interpolated String literals are no longer frozen when
|
||||
`# frozen-string-literal: true` is used. [[Feature #17104]]
|
||||
|
||||
## Command line options
|
||||
|
||||
### `--help` option
|
||||
|
@ -373,6 +376,7 @@ Excluding feature bug fixes.
|
|||
[Feature #16746]: https://bugs.ruby-lang.org/issues/16746
|
||||
[Feature #16754]: https://bugs.ruby-lang.org/issues/16754
|
||||
[Feature #16828]: https://bugs.ruby-lang.org/issues/16828
|
||||
[Feature #17104]: https://bugs.ruby-lang.org/issues/17104
|
||||
[Misc #16961]: https://bugs.ruby-lang.org/issues/16961
|
||||
[Feature #17122]: https://bugs.ruby-lang.org/issues/17122
|
||||
[GH-2991]: https://github.com/ruby/ruby/pull/2991
|
||||
|
|
|
@ -89,8 +89,6 @@ tests = [
|
|||
[ 'putiseq', %q{ -> { true }.() }, ],
|
||||
[ 'putstring', %q{ "true" }, ],
|
||||
[ 'tostring / concatstrings', %q{ "#{true}" }, ],
|
||||
[ 'freezestring', %q{ "#{true}" }, fsl, ],
|
||||
[ 'freezestring', %q{ "#{true}" }, '-d', fsl, ],
|
||||
[ 'toregexp', %q{ /#{true}/ =~ "true" && $~ }, ],
|
||||
[ 'intern', %q{ :"#{true}" }, ],
|
||||
|
||||
|
|
60
compile.c
60
compile.c
|
@ -2692,21 +2692,6 @@ iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
|
|||
}
|
||||
}
|
||||
|
||||
static int
|
||||
same_debug_pos_p(LINK_ELEMENT *iobj1, LINK_ELEMENT *iobj2)
|
||||
{
|
||||
VALUE debug1 = OPERAND_AT(iobj1, 0);
|
||||
VALUE debug2 = OPERAND_AT(iobj2, 0);
|
||||
if (debug1 == debug2) return TRUE;
|
||||
if (!RB_TYPE_P(debug1, T_ARRAY)) return FALSE;
|
||||
if (!RB_TYPE_P(debug2, T_ARRAY)) return FALSE;
|
||||
if (RARRAY_LEN(debug1) != 2) return FALSE;
|
||||
if (RARRAY_LEN(debug2) != 2) return FALSE;
|
||||
if (RARRAY_AREF(debug1, 0) != RARRAY_AREF(debug2, 0)) return FALSE;
|
||||
if (RARRAY_AREF(debug1, 1) != RARRAY_AREF(debug2, 1)) return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
is_frozen_putstring(INSN *insn, VALUE *op)
|
||||
{
|
||||
|
@ -3229,10 +3214,8 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
|
|||
* =>
|
||||
* concatstrings N+M-1
|
||||
*/
|
||||
LINK_ELEMENT *next = iobj->link.next, *freeze = 0;
|
||||
LINK_ELEMENT *next = iobj->link.next;
|
||||
INSN *jump = 0;
|
||||
if (IS_INSN(next) && IS_INSN_ID(next, freezestring))
|
||||
next = (freeze = next)->next;
|
||||
if (IS_INSN(next) && IS_INSN_ID(next, jump))
|
||||
next = get_destination_insn(jump = (INSN *)next);
|
||||
if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
|
||||
|
@ -3248,44 +3231,15 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
|
|||
OPERAND_AT(jump, 0) = (VALUE)label;
|
||||
}
|
||||
label->refcnt++;
|
||||
if (freeze && IS_NEXT_INSN_ID(next, freezestring)) {
|
||||
if (same_debug_pos_p(freeze, next->next)) {
|
||||
ELEM_REMOVE(freeze);
|
||||
}
|
||||
else {
|
||||
next = next->next;
|
||||
}
|
||||
}
|
||||
ELEM_INSERT_NEXT(next, &label->link);
|
||||
CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
|
||||
}
|
||||
else {
|
||||
if (freeze) ELEM_REMOVE(freeze);
|
||||
ELEM_REMOVE(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_INSN_ID(iobj, freezestring) &&
|
||||
NIL_P(OPERAND_AT(iobj, 0)) &&
|
||||
IS_NEXT_INSN_ID(&iobj->link, send)) {
|
||||
INSN *niobj = (INSN *)iobj->link.next;
|
||||
const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
|
||||
|
||||
/*
|
||||
* freezestring nil # no debug_info
|
||||
* send <:+@, 0, ARG_SIMPLE> # :-@, too
|
||||
* =>
|
||||
* send <:+@, 0, ARG_SIMPLE> # :-@, too
|
||||
*/
|
||||
if ((vm_ci_mid(ci) == idUPlus || vm_ci_mid(ci) == idUMinus) &&
|
||||
(vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE) &&
|
||||
vm_ci_argc(ci) == 0) {
|
||||
ELEM_REMOVE(list);
|
||||
return COMPILE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (do_tailcallopt &&
|
||||
(IS_INSN_ID(iobj, send) ||
|
||||
IS_INSN_ID(iobj, opt_aref_with) ||
|
||||
|
@ -8402,18 +8356,6 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
|
|||
if (popped) {
|
||||
ADD_INSN(ret, line, pop);
|
||||
}
|
||||
else {
|
||||
if (ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal) {
|
||||
VALUE debug_info = Qnil;
|
||||
if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
|
||||
debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX(line));
|
||||
}
|
||||
ADD_INSN1(ret, line, freezestring, debug_info);
|
||||
if (!NIL_P(debug_info)) {
|
||||
RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_freeze(debug_info));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_XSTR:{
|
||||
|
|
10
insns.def
10
insns.def
|
@ -390,16 +390,6 @@ tostring
|
|||
val = rb_obj_as_string_result(str, val);
|
||||
}
|
||||
|
||||
/* Freeze (dynamically) created strings. if debug_info is given, set it. */
|
||||
DEFINE_INSN
|
||||
freezestring
|
||||
(VALUE debug_info)
|
||||
(VALUE str)
|
||||
(VALUE str)
|
||||
{
|
||||
vm_freezestring(str, debug_info);
|
||||
}
|
||||
|
||||
/* compile str to Regexp and push it.
|
||||
opt is the option for the Regexp.
|
||||
*/
|
||||
|
|
|
@ -291,4 +291,21 @@ describe "Ruby String interpolation" do
|
|||
|
||||
-> { "#{a} #{b}" }.should raise_error(Encoding::CompatibilityError)
|
||||
end
|
||||
|
||||
it "creates a non-frozen String" do
|
||||
code = <<~'RUBY'
|
||||
"a#{6*7}c"
|
||||
RUBY
|
||||
eval(code).should_not.frozen?
|
||||
end
|
||||
|
||||
ruby_version_is "3.0" do
|
||||
it "creates a non-frozen String when # frozen-string-literal: true is used" do
|
||||
code = <<~'RUBY'
|
||||
# frozen-string-literal: true
|
||||
"a#{6*7}c"
|
||||
RUBY
|
||||
eval(code).should_not.frozen?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -187,8 +187,8 @@ class TestISeq < Test::Unit::TestCase
|
|||
s1, s2, s3, s4 = compile(code, line, {frozen_string_literal: true}).eval
|
||||
assert_predicate(s1, :frozen?)
|
||||
assert_predicate(s2, :frozen?)
|
||||
assert_predicate(s3, :frozen?)
|
||||
assert_predicate(s4, :frozen?)
|
||||
assert_not_predicate(s3, :frozen?)
|
||||
assert_predicate(s4, :frozen?) # should probably not be frozen, but unrealistic code
|
||||
end
|
||||
|
||||
# Safe call chain is not optimized when Coverage is running.
|
||||
|
|
|
@ -247,14 +247,6 @@ class TestJIT < Test::Unit::TestCase
|
|||
assert_compile_once('"a#{}b" + "c"', result_inspect: '"abc"', insns: %i[putstring concatstrings tostring])
|
||||
end
|
||||
|
||||
def test_compile_insn_freezestring
|
||||
assert_eval_with_jit("#{<<~"begin;"}\n#{<<~'end;'}", stdout: 'true', success_count: 1, insns: %i[freezestring])
|
||||
begin;
|
||||
# frozen_string_literal: true
|
||||
print proc { "#{true}".frozen? }.call
|
||||
end;
|
||||
end
|
||||
|
||||
def test_compile_insn_toregexp
|
||||
assert_compile_once('/#{true}/ =~ "true"', result_inspect: '0', insns: %i[toregexp])
|
||||
end
|
||||
|
|
|
@ -187,7 +187,7 @@ class TestRubyLiteral < Test::Unit::TestCase
|
|||
if defined?(RubyVM::InstructionSequence.compile_option) and
|
||||
RubyVM::InstructionSequence.compile_option.key?(:debug_frozen_string_literal)
|
||||
def test_debug_frozen_string
|
||||
src = 'n = 1; _="foo#{n ? "-#{n}" : ""}"'; f = "test.rb"; n = 1
|
||||
src = '_="foo-1"'; f = "test.rb"; n = 1
|
||||
opt = {frozen_string_literal: true, debug_frozen_string_literal: true}
|
||||
str = RubyVM::InstructionSequence.compile(src, f, f, n, **opt).eval
|
||||
assert_equal("foo-1", str)
|
||||
|
|
|
@ -1014,11 +1014,11 @@ class TestRubyOptions < Test::Unit::TestCase
|
|||
err = !freeze ? [] : debug ? with_debug_pat : wo_debug_pat
|
||||
[
|
||||
['"foo" << "bar"', err],
|
||||
['"foo#{123}bar" << "bar"', err],
|
||||
['"foo#{123}bar" << "bar"', []],
|
||||
['+"foo#{123}bar" << "bar"', []],
|
||||
['-"foo#{123}bar" << "bar"', freeze && debug ? with_debug_pat : wo_debug_pat],
|
||||
['-"foo#{123}bar" << "bar"', wo_debug_pat],
|
||||
].each do |code, expected|
|
||||
assert_in_out_err(opt, code, [], expected, [opt, code])
|
||||
assert_in_out_err(opt, code, [], expected, "#{opt} #{code}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3816,15 +3816,6 @@ vm_get_special_object(const VALUE *const reg_ep,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
vm_freezestring(VALUE str, VALUE debug)
|
||||
{
|
||||
if (!NIL_P(debug)) {
|
||||
rb_ivar_set(str, id_debug_created_info, debug);
|
||||
}
|
||||
rb_str_freeze(str);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
vm_concat_array(VALUE ary1, VALUE ary2st)
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче