summaryrefslogtreecommitdiff
path: root/compile.c
diff options
context:
space:
mode:
authorÉtienne Barrié <[email protected]>2023-12-01 11:33:00 +0100
committerJean Boussier <[email protected]>2024-03-19 09:26:49 +0100
commit12be40ae6be78ac41e8e3f3c313cc6f63e7fa6c4 (patch)
treef6b81fac770da6b705557623224dbf9b9c2d2847 /compile.c
parent86b15316a748a579dd4fd4df42b6db42accebdc2 (diff)
Implement chilled strings
[Feature #20205] As a path toward enabling frozen string literals by default in the future, this commit introduce "chilled strings". From a user perspective chilled strings pretend to be frozen, but on the first attempt to mutate them, they lose their frozen status and emit a warning rather than to raise a `FrozenError`. Implementation wise, `rb_compile_option_struct.frozen_string_literal` is no longer a boolean but a tri-state of `enabled/disabled/unset`. When code is compiled with frozen string literals neither explictly enabled or disabled, string literals are compiled with a new `putchilledstring` instruction. This instruction is identical to `putstring` except it marks the String with the `STR_CHILLED (FL_USER3)` and `FL_FREEZE` flags. Chilled strings have the `FL_FREEZE` flag as to minimize the need to check for chilled strings across the codebase, and to improve compatibility with C extensions. Notes: - `String#freeze`: clears the chilled flag. - `String#-@`: acts as if the string was mutable. - `String#+@`: acts as if the string was mutable. - `String#clone`: copies the chilled flag. Co-authored-by: Jean Boussier <[email protected]>
Diffstat (limited to 'compile.c')
-rw-r--r--compile.c17
1 files changed, 13 insertions, 4 deletions
diff --git a/compile.c b/compile.c
index 099341bcf6..5516f64f54 100644
--- a/compile.c
+++ b/compile.c
@@ -4723,7 +4723,7 @@ frozen_string_literal_p(const rb_iseq_t *iseq)
return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
}
-static inline int
+static inline bool
static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
{
switch (nd_type(node)) {
@@ -10365,12 +10365,18 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
debugp_param("nd_lit", get_string_value(node));
if (!popped) {
VALUE lit = get_string_value(node);
- if (!frozen_string_literal_p(iseq)) {
+ switch (ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal) {
+ case ISEQ_FROZEN_STRING_LITERAL_UNSET:
+ lit = rb_fstring(lit);
+ ADD_INSN1(ret, node, putchilledstring, lit);
+ RB_OBJ_WRITTEN(iseq, Qundef, lit);
+ break;
+ case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
lit = rb_fstring(lit);
ADD_INSN1(ret, node, putstring, lit);
RB_OBJ_WRITTEN(iseq, Qundef, lit);
- }
- else {
+ break;
+ case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX(line));
lit = rb_str_dup(lit);
@@ -10382,6 +10388,9 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
ADD_INSN1(ret, node, putobject, lit);
RB_OBJ_WRITTEN(iseq, Qundef, lit);
+ break;
+ default:
+ rb_bug("invalid frozen_string_literal");
}
}
break;