Skip to content

Commit 0ed63ea

Browse files
Earlopainst0012
authored andcommitted
Interpolation with only string literals must not be frozen
Basically a redo of ruby@a1403fb but respecting the frozen string literal magic comment Fixes [Bug #21187]
1 parent 90f9def commit 0ed63ea

3 files changed

Lines changed: 28 additions & 9 deletions

File tree

prism/prism.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5280,6 +5280,12 @@ pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_
52805280

52815281
switch (PM_NODE_TYPE(part)) {
52825282
case PM_STRING_NODE:
5283+
// If inner string is not frozen, it stops being a static literal. We should *not* clear other flags,
5284+
// because concatenating two frozen strings (`'foo' 'bar'`) is still frozen. This holds true for
5285+
// as long as this interpolation only consists of other string literals.
5286+
if (!PM_NODE_FLAG_P(part, PM_STRING_FLAGS_FROZEN)) {
5287+
pm_node_flag_unset((pm_node_t *) node, PM_NODE_FLAG_STATIC_LITERAL);
5288+
}
52835289
part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
52845290
break;
52855291
case PM_INTERPOLATED_STRING_NODE:

prism_compile.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@ parse_regexp_concat(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm
558558
static void pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node);
559559

560560
static int
561-
pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node, rb_encoding *implicit_regexp_encoding, rb_encoding *explicit_regexp_encoding, bool mutable_result)
561+
pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node, rb_encoding *implicit_regexp_encoding, rb_encoding *explicit_regexp_encoding, bool mutable_result, bool frozen_result)
562562
{
563563
int stack_size = 0;
564564
size_t parts_size = parts->size;
@@ -668,10 +668,15 @@ pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const
668668
if (RTEST(current_string)) {
669669
current_string = rb_fstring(current_string);
670670

671-
if (stack_size == 0 && (interpolated || mutable_result)) {
672-
PUSH_INSN1(ret, current_location, putstring, current_string);
673-
}
674-
else {
671+
if (stack_size == 0) {
672+
if (frozen_result) {
673+
PUSH_INSN1(ret, current_location, putobject, current_string);
674+
} else if (mutable_result || interpolated) {
675+
PUSH_INSN1(ret, current_location, putstring, current_string);
676+
} else {
677+
PUSH_INSN1(ret, current_location, putchilledstring, current_string);
678+
}
679+
} else {
675680
PUSH_INSN1(ret, current_location, putobject, current_string);
676681
}
677682

@@ -692,7 +697,7 @@ pm_compile_regexp_dynamic(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_
692697
rb_encoding *explicit_regexp_encoding = parse_regexp_encoding(scope_node, node);
693698
rb_encoding *implicit_regexp_encoding = explicit_regexp_encoding != NULL ? explicit_regexp_encoding : scope_node->encoding;
694699

695-
int length = pm_interpolated_node_compile(iseq, parts, node_location, ret, popped, scope_node, implicit_regexp_encoding, explicit_regexp_encoding, false);
700+
int length = pm_interpolated_node_compile(iseq, parts, node_location, ret, popped, scope_node, implicit_regexp_encoding, explicit_regexp_encoding, false, false);
696701
PUSH_INSN2(ret, *node_location, toregexp, INT2FIX(parse_regexp_flags(node) & 0xFF), INT2FIX(length));
697702
}
698703

@@ -9571,7 +9576,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
95719576
}
95729577
else {
95739578
const pm_interpolated_string_node_t *cast = (const pm_interpolated_string_node_t *) node;
9574-
int length = pm_interpolated_node_compile(iseq, &cast->parts, &location, ret, popped, scope_node, NULL, NULL, !PM_NODE_FLAG_P(cast, PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN));
9579+
int length = pm_interpolated_node_compile(iseq, &cast->parts, &location, ret, popped, scope_node, NULL, NULL, PM_NODE_FLAG_P(cast, PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE), PM_NODE_FLAG_P(cast, PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN));
95759580
if (length > 1) PUSH_INSN1(ret, location, concatstrings, INT2FIX(length));
95769581
if (popped) PUSH_INSN(ret, location, pop);
95779582
}
@@ -9582,7 +9587,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
95829587
// :"foo #{bar}"
95839588
// ^^^^^^^^^^^^^
95849589
const pm_interpolated_symbol_node_t *cast = (const pm_interpolated_symbol_node_t *) node;
9585-
int length = pm_interpolated_node_compile(iseq, &cast->parts, &location, ret, popped, scope_node, NULL, NULL, false);
9590+
int length = pm_interpolated_node_compile(iseq, &cast->parts, &location, ret, popped, scope_node, NULL, NULL, false, false);
95869591

95879592
if (length > 1) {
95889593
PUSH_INSN1(ret, location, concatstrings, INT2FIX(length));
@@ -9604,7 +9609,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
96049609

96059610
PUSH_INSN(ret, location, putself);
96069611

9607-
int length = pm_interpolated_node_compile(iseq, &cast->parts, &location, ret, false, scope_node, NULL, NULL, false);
9612+
int length = pm_interpolated_node_compile(iseq, &cast->parts, &location, ret, false, scope_node, NULL, NULL, false, false);
96089613
if (length > 1) PUSH_INSN1(ret, location, concatstrings, INT2FIX(length));
96099614

96109615
PUSH_SEND_WITH_FLAG(ret, location, idBackquote, INT2NUM(1), INT2FIX(VM_CALL_FCALL | VM_CALL_ARGS_SIMPLE));

spec/ruby/core/string/chilled_string_spec.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@
4747
input.should == "chilled-mutated"
4848
end
4949

50+
it "emits a warning for concatenated strings" do
51+
input = "still" "+chilled"
52+
-> {
53+
input << "-mutated"
54+
}.should complain(/literal string will be frozen in the future/)
55+
input.should == "still+chilled-mutated"
56+
end
57+
5058
it "emits a warning on singleton_class creation" do
5159
-> {
5260
"chilled".singleton_class

0 commit comments

Comments
 (0)