Repository: ruby/prism
Pull request #2603 (2024-03-15 12:26:13)

Add PM_STRING_FLAGS_FROZEN / PM_STRING_FLAGS_MUTABLE on PM_SOURCE_FILE_NODE
For all intent and purposes, `__FILE__` is a string literal subject to the `# frozen_string_literal: true/false` comment and to the global `--enable-frozen-string-literal / --disable-frozen-string-literal` CLI flags.

casperisfine: Done.
kddnewton: Sorry to keep going back and forth — can you make it the first field? We have a convention that the flags are always the first because eventually we're going to expose it on all of them as the first child.
casperisfine: > can you make it the first field?

Done.
kddnewton: It's probably going to generate a bunch of snapshot changes, you can just commit those.
casperisfine: Indeed. I'm running into `Assertion failed: (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)), function pm_static_literal_inspect, file static_literals.c, line 438.` though. Trying to figure it out.

Patch:
diff --git a/config.yml b/config.yml
index ab4aeae7..381a33a8 100644
--- a/config.yml
+++ b/config.yml
@@ -248,7 +248,6 @@ warnings:
   - INTEGER_IN_FLIP_FLOP
   - INVALID_CHARACTER
   - INVALID_NUMBERED_REFERENCE
-  - INVALID_SHAREABLE_CONSTANT_VALUE
   - KEYWORD_EOL
   - LITERAL_IN_CONDITION_DEFAULT
   - LITERAL_IN_CONDITION_VERBOSE
@@ -668,15 +667,6 @@ flags:
       - name: FORCED_US_ASCII_ENCODING
         comment: "internal bytes forced the encoding to US-ASCII"
     comment: Flags for regular expression and match last line nodes.
-  - name: ShareableConstantNodeFlags
-    values:
-      - name: LITERAL
-        comment: "constant writes that should be modified with shareable constant value literal"
-      - name: EXPERIMENTAL_EVERYTHING
-        comment: "constant writes that should be modified with shareable constant value experimental everything"
-      - name: EXPERIMENTAL_COPY
-        comment: "constant writes that should be modified with shareable constant value experimental copy"
-    comment: Flags for shareable constant nodes.
   - name: StringFlags
     values:
       - name: FORCED_UTF8_ENCODING
@@ -3073,29 +3063,6 @@ nodes:
 
           self
           ^^^^
-  - name: ShareableConstantNode
-    fields:
-      - name: flags
-        type: flags
-        kind: ShareableConstantNodeFlags
-      - name: write
-        type: node
-        kind:
-          - ConstantWriteNode
-          - ConstantAndWriteNode
-          - ConstantOrWriteNode
-          - ConstantOperatorWriteNode
-          - ConstantPathWriteNode
-          - ConstantPathAndWriteNode
-          - ConstantPathOrWriteNode
-          - ConstantPathOperatorWriteNode
-        comment: The constant write that should be modified with the shareability state.
-    comment: |
-      This node wraps a constant write to indicate that when the value is written, it should have its shareability state modified.
-
-          # shareable_constant_value: literal
-          C = { a: 1 }
-          ^^^^^^^^^^^^
   - name: SingletonClassNode
     fields:
       - name: locals
@@ -3123,6 +3090,9 @@ nodes:
           ^^^^^^^^^^^^
   - name: SourceFileNode
     fields:
+      - name: flags
+        type: flags
+        kind: StringFlags
       - name: filepath
         type: string
     comment: |
diff --git a/include/prism/parser.h b/include/prism/parser.h
index b685fa37..619358c5 100644
--- a/include/prism/parser.h
+++ b/include/prism/parser.h
@@ -448,13 +448,6 @@ typedef struct {
     void (*callback)(void *data, pm_parser_t *parser, pm_token_t *token);
 } pm_lex_callback_t;
 
-/** The type of shareable constant value that can be set. */
-typedef uint8_t pm_shareable_constant_value_t;
-static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_NONE = 0x0;
-static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_LITERAL = 0x1;
-static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING = 0x2;
-static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY = 0x4;
-
 /**
  * This struct represents a node in a linked list of scopes. Some scopes can see
  * into their parent scopes, while others cannot.
@@ -494,12 +487,6 @@ typedef struct pm_scope {
      */
     int8_t numbered_parameters;
 
-    /**
-     * The current state of constant shareability for this scope. This is
-     * changed by magic shareable_constant_value comments.
-     */
-    pm_shareable_constant_value_t shareable_constant;
-
     /**
      * A boolean indicating whether or not this scope can see into its parent.
      * If closed is true, then the scope cannot see into its parent.
diff --git a/lib/prism/translation/parser/compiler.rb b/lib/prism/translation/parser/compiler.rb
index 0503d003..50c47c06 100644
--- a/lib/prism/translation/parser/compiler.rb
+++ b/lib/prism/translation/parser/compiler.rb
@@ -953,35 +953,14 @@ module Prism
         def visit_interpolated_string_node(node)
           if node.heredoc?
             children, closing = visit_heredoc(node)
-
-            return builder.string_compose(token(node.opening_loc), children, closing)
-          end
-
-          parts = if node.parts.one? { |part| part.type == :string_node }
-            node.parts.flat_map do |node|
-              if node.type == :string_node && node.unescaped.lines.count >= 2
-                start_offset = node.content_loc.start_offset
-
-                node.unescaped.lines.map do |line|
-                  end_offset = start_offset + line.length
-                  offsets = srange_offsets(start_offset, end_offset)
-                  start_offset = end_offset
-
-                  builder.string_internal([line, offsets])
-                end
-              else
-                visit(node)
-              end
-            end
+            builder.string_compose(token(node.opening_loc), children, closing)
           else
-            visit_all(node.parts)
+            builder.string_compose(
+              token(node.opening_loc),
+              visit_all(node.parts),
+              token(node.closing_loc)
+            )
           end
-
-          builder.string_compose(
-            token(node.opening_loc),
-            parts,
-            token(node.closing_loc)
-          )
         end
 
         # :"foo #{bar}"
@@ -1444,11 +1423,6 @@ module Prism
           builder.self(token(node.location))
         end
 
-        # A shareable constant.
-        def visit_shareable_constant_node(node)
-          visit(node.write)
-        end
-
         # class << self; end
         # ^^^^^^^^^^^^^^^^^^
         def visit_singleton_class_node(node)
@@ -1513,17 +1487,17 @@ module Prism
           elsif node.opening == "?"
             builder.character([node.unescaped, srange(node.location)])
           else
-            parts = if node.content.lines.count <= 1 || node.unescaped.lines.count <= 1
+            parts = if node.unescaped.lines.count <= 1
               [builder.string_internal([node.unescaped, srange(node.content_loc)])]
             else
               start_offset = node.content_loc.start_offset
 
-              [node.content.lines, node.unescaped.lines].transpose.map do |content_line, unescaped_line|
-                end_offset = start_offset + content_line.length
+              node.unescaped.lines.map do |line|
+                end_offset = start_offset + line.length
                 offsets = srange_offsets(start_offset, end_offset)
                 start_offset = end_offset
 
-                builder.string_internal([unescaped_line, offsets])
+                builder.string_internal([line, offsets])
               end
             end
 
diff --git a/lib/prism/translation/parser/lexer.rb b/lib/prism/translation/parser/lexer.rb
index 7febca44..9cf86476 100644
--- a/lib/prism/translation/parser/lexer.rb
+++ b/lib/prism/translation/parser/lexer.rb
@@ -295,24 +295,8 @@ module Prism
               unless (lines = token.value.lines).one?
                 start_offset = offset_cache[token.location.start_offset]
                 lines.map do |line|
-                  newline = line.end_with?("\r\n") ? "\r\n" : "\n"
-                  chomped_line = line.chomp
-                  if match = chomped_line.match(/(?<backslashes>\\+)\z/)
-                    adjustment = match[:backslashes].size / 2
-                    adjusted_line = chomped_line.delete_suffix("\\" * adjustment)
-                    if match[:backslashes].size.odd?
-                      adjusted_line.delete_suffix!("\\")
-                      adjustment += 2
-                    else
-                      adjusted_line << newline
-                    end
-                  else
-                    adjusted_line = line
-                    adjustment = 0
-                  end
-
-                  end_offset = start_offset + adjusted_line.length + adjustment
-                  tokens << [:tSTRING_CONTENT, [adjusted_line, Range.new(source_buffer, offset_cache[start_offset], offset_cache[end_offset])]]
+                  end_offset = start_offset + line.length
+                  tokens << [:tSTRING_CONTENT, [line, Range.new(source_buffer, offset_cache[start_offset], offset_cache[end_offset])]]
                   start_offset = end_offset
                 end
                 next
diff --git a/lib/prism/translation/ripper.rb b/lib/prism/translation/ripper.rb
index 3c06f6a4..9f269f9e 100644
--- a/lib/prism/translation/ripper.rb
+++ b/lib/prism/translation/ripper.rb
@@ -2858,11 +2858,6 @@ module Prism
         on_var_ref(on_kw("self"))
       end
 
-      # A shareable constant.
-      def visit_shareable_constant_node(node)
-        visit(node.write)
-      end
-
       # class << self; end
       # ^^^^^^^^^^^^^^^^^^
       def visit_singleton_class_node(node)
diff --git a/lib/prism/translation/ruby_parser.rb b/lib/prism/translation/ruby_parser.rb
index 108e6c69..46640618 100644
--- a/lib/prism/translation/ruby_parser.rb
+++ b/lib/prism/translation/ruby_parser.rb
@@ -1274,11 +1274,6 @@ module Prism
           s(node, :self)
         end
 
-        # A shareable constant.
-        def visit_shareable_constant_node(node)
-          visit(node.write)
-        end
-
         # class << self; end
         # ^^^^^^^^^^^^^^^^^^
         def visit_singleton_class_node(node)
diff --git a/src/prism.c b/src/prism.c
index 96435a38..06528932 100644
--- a/src/prism.c
+++ b/src/prism.c
@@ -5731,25 +5731,6 @@ pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
     return node;
 }
 
-/**
- * Allocate and initialize a new ShareableConstantNode node.
- */
-static pm_shareable_constant_node_t *
-pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
-    pm_shareable_constant_node_t *node = PM_ALLOC_NODE(parser, pm_shareable_constant_node_t);
-
-    *node = (pm_shareable_constant_node_t) {
-        {
-            .type = PM_SHAREABLE_CONSTANT_NODE,
-            .flags = (pm_node_flags_t) value,
-            .location = PM_LOCATION_NODE_VALUE(write)
-        },
-        .write = write
-    };
-
-    return node;
-}
-
 /**
  * Allocate a new SingletonClassNode node.
  */
@@ -5801,10 +5782,21 @@ pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword)
     pm_source_file_node_t *node = PM_ALLOC_NODE(parser, pm_source_file_node_t);
     assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
 
+    pm_node_flags_t flags = 0;
+
+    switch (parser->frozen_string_literal) {
+        case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
+            flags |= PM_STRING_FLAGS_MUTABLE;
+            break;
+        case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
+            flags |= PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
+            break;
+    }
+
     *node = (pm_source_file_node_t) {
         {
             .type = PM_SOURCE_FILE_NODE,
-            .flags = PM_NODE_FLAG_STATIC_LITERAL,
+            .flags = flags,
             .location = PM_LOCATION_TOKEN_VALUE(file_keyword),
         },
         .filepath = parser->filepath
@@ -6764,7 +6756,6 @@ pm_parser_scope_push(pm_parser_t *parser, bool closed) {
         .locals = { 0 },
         .parameters = PM_SCOPE_PARAMETERS_NONE,
         .numbered_parameters = PM_SCOPE_NUMBERED_PARAMETERS_NONE,
-        .shareable_constant = (closed || parser->current_scope == NULL) ? PM_SCOPE_SHAREABLE_CONSTANT_NONE : parser->current_scope->shareable_constant,
         .closed = closed
     };
 
@@ -6810,27 +6801,6 @@ pm_parser_scope_forwarding_keywords_check(pm_parser_t *parser, const pm_token_t
     pm_parser_scope_forwarding_param_check(parser, token, PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH);
 }
 
-/**
- * Get the current state of constant shareability.
- */
-static inline pm_shareable_constant_value_t
-pm_parser_scope_shareable_constant_get(pm_parser_t *parser) {
-    return parser->current_scope->shareable_constant;
-}
-
-/**
- * Set the current state of constant shareability. We'll set it on all of the
- * open scopes so that reads are quick.
- */
-static void
-pm_parser_scope_shareable_constant_set(pm_parser_t *parser, pm_shareable_constant_value_t shareable_constant) {
-    pm_scope_t *scope = parser->current_scope;
-
-    do {
-        scope->shareable_constant = shareable_constant;
-    } while (!scope->closed && (scope = scope->previous) != NULL);
-}
-
 /**
  * Save the current param name as the return value and set it to the given
  * constant id.
@@ -7386,28 +7356,6 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
             }
         }
 
-        // If we have hit a ractor pragma, attempt to lex that.
-        uint32_t value_length = (uint32_t) (value_end - value_start);
-        if (key_length == 24 && pm_strncasecmp(key_source, (const uint8_t *) "shareable_constant_value", 24) == 0) {
-            if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "none", 4) == 0) {
-                pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
-            } else if (value_length == 7 && pm_strncasecmp(value_start, (const uint8_t *) "literal", 7) == 0) {
-                pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
-            } else if (value_length == 23 && pm_strncasecmp(value_start, (const uint8_t *) "experimental_everything", 23) == 0) {
-                pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
-            } else if (value_length == 17 && pm_strncasecmp(value_start, (const uint8_t *) "experimental_copy", 17) == 0) {
-                pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
-            } else {
-                PM_PARSER_WARN_TOKEN_FORMAT(
-                    parser,
-                    parser->current,
-                    PM_WARN_INVALID_SHAREABLE_CONSTANT_VALUE,
-                    (int) value_length,
-                    (const char *) value_start
-                );
-            }
-        }
-
         // When we're done, we want to free the string in case we had to
         // allocate memory for it.
         pm_string_free(&key);
@@ -12054,21 +12002,6 @@ parse_target_validate(pm_parser_t *parser, pm_node_t *target) {
     return result;
 }
 
-/**
- * Potentially wrap a constant write node in a shareable constant node depending
- * on the current state.
- */
-static pm_node_t *
-parse_shareable_constant_write(pm_parser_t *parser, pm_node_t *write) {
-    pm_shareable_constant_value_t shareable_constant = pm_parser_scope_shareable_constant_get(parser);
-
-    if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
-        return (pm_node_t *) pm_shareable_constant_node_create(parser, write, shareable_constant);
-    }
-
-    return write;
-}
-
 /**
  * Convert the given node into a valid write node.
  */
@@ -12083,17 +12016,15 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
             pm_node_destroy(parser, target);
             return (pm_node_t *) node;
         }
-        case PM_CONSTANT_PATH_NODE: {
-            pm_node_t *node = (pm_node_t *) pm_constant_path_write_node_create(parser, (pm_constant_path_node_t *) target, operator, value);
-            return parse_shareable_constant_write(parser, node);
-        }
+        case PM_CONSTANT_PATH_NODE:
+            return (pm_node_t *) pm_constant_path_write_node_create(parser, (pm_constant_path_node_t *) target, operator, value);
         case PM_CONSTANT_READ_NODE: {
-            pm_node_t *node = (pm_node_t *) pm_constant_write_node_create(parser, (pm_constant_read_node_t *) target, operator, value);
+            pm_constant_write_node_t *node = pm_constant_write_node_create(parser, (pm_constant_read_node_t *) target, operator, value);
             if (context_def_p(parser)) {
-                pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
+                pm_parser_err_node(parser, (pm_node_t *) node, PM_ERR_WRITE_TARGET_IN_METHOD);
             }
             pm_node_destroy(parser, target);
-            return parse_shareable_constant_write(parser, node);
+            return (pm_node_t *) node;
         }
         case PM_BACK_REFERENCE_READ_NODE:
         case PM_NUMBERED_REFERENCE_READ_NODE:
@@ -18034,18 +17965,16 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
                     parser_lex(parser);
 
                     pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
-                    pm_node_t *write = (pm_node_t *) pm_constant_path_and_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value);
-
-                    return parse_shareable_constant_write(parser, write);
+                    return (pm_node_t *) pm_constant_path_and_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value);
                 }
                 case PM_CONSTANT_READ_NODE: {
                     parser_lex(parser);
 
                     pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
-                    pm_node_t *write = (pm_node_t *) pm_constant_and_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value);
+                    pm_node_t *result = (pm_node_t *) pm_constant_and_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value);
 
                     pm_node_destroy(parser, node);
-                    return parse_shareable_constant_write(parser, write);
+                    return result;
                 }
                 case PM_INSTANCE_VARIABLE_READ_NODE: {
                     parser_lex(parser);
@@ -18147,18 +18076,16 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
                     parser_lex(parser);
 
                     pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
-                    pm_node_t *write = (pm_node_t *) pm_constant_path_or_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value);
-
-                    return parse_shareable_constant_write(parser, write);
+                    return (pm_node_t *) pm_constant_path_or_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value);
                 }
                 case PM_CONSTANT_READ_NODE: {
                     parser_lex(parser);
 
                     pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
-                    pm_node_t *write = (pm_node_t *) pm_constant_or_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value);
+                    pm_node_t *result = (pm_node_t *) pm_constant_or_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value);
 
                     pm_node_destroy(parser, node);
-                    return parse_shareable_constant_write(parser, write);
+                    return result;
                 }
                 case PM_INSTANCE_VARIABLE_READ_NODE: {
                     parser_lex(parser);
@@ -18270,18 +18197,16 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
                     parser_lex(parser);
 
                     pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
-                    pm_node_t *write = (pm_node_t *) pm_constant_path_operator_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value);
-
-                    return parse_shareable_constant_write(parser, write);
+                    return (pm_node_t *) pm_constant_path_operator_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value);
                 }
                 case PM_CONSTANT_READ_NODE: {
                     parser_lex(parser);
 
                     pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
-                    pm_node_t *write = (pm_node_t *) pm_constant_operator_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value);
+                    pm_node_t *result = (pm_node_t *) pm_constant_operator_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value);
 
                     pm_node_destroy(parser, node);
-                    return parse_shareable_constant_write(parser, write);
+                    return result;
                 }
                 case PM_INSTANCE_VARIABLE_READ_NODE: {
                     parser_lex(parser);
diff --git a/templates/src/diagnostic.c.erb b/templates/src/diagnostic.c.erb
index 1c311447..2a14c0dc 100644
--- a/templates/src/diagnostic.c.erb
+++ b/templates/src/diagnostic.c.erb
@@ -327,7 +327,6 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
     [PM_WARN_FLOAT_OUT_OF_RANGE]                = { "Float %.*s%s out of range", PM_WARNING_LEVEL_VERBOSE },
     [PM_WARN_INTEGER_IN_FLIP_FLOP]              = { "integer literal in flip-flop", PM_WARNING_LEVEL_DEFAULT },
     [PM_WARN_INVALID_CHARACTER]                 = { "invalid character syntax; use %s%s%s", PM_WARNING_LEVEL_DEFAULT },
-    [PM_WARN_INVALID_SHAREABLE_CONSTANT_VALUE]  = { "invalid value for shareable_constant_value: %.*s", PM_WARNING_LEVEL_VERBOSE },
     [PM_WARN_INVALID_NUMBERED_REFERENCE]        = { "'%.*s' is too big for a number variable, always nil", PM_WARNING_LEVEL_DEFAULT },
     [PM_WARN_KEYWORD_EOL]                       = { "`%.*s` at the end of line without an expression", PM_WARNING_LEVEL_VERBOSE },
     [PM_WARN_LITERAL_IN_CONDITION_DEFAULT]      = { "%sliteral in %s", PM_WARNING_LEVEL_DEFAULT },


Test patch:
diff --git a/test/prism/fixtures/dstring.txt b/test/prism/fixtures/dstring.txt
index 085e0c68..b7a0958d 100644
--- a/test/prism/fixtures/dstring.txt
+++ b/test/prism/fixtures/dstring.txt
@@ -1,29 +1,2 @@
 "foo
   bar"
-
-"foo
-  #{bar}"
-
-"fo
-o" "ba
-r"
-
-"
-foo\
-"
-
-"
-foo\\
-"
-
-"
-foo\\\
-"
-
-"
-foo\\\\
-"
-
-"
-foo\\\\\
-"
diff --git a/test/prism/location_test.rb b/test/prism/location_test.rb
index c7ce248b..46ec7f4e 100644
--- a/test/prism/location_test.rb
+++ b/test/prism/location_test.rb
@@ -781,15 +781,6 @@ module Prism
       assert_location(SelfNode, "self")
     end
 
-    def test_ShareableConstantNode
-      source = <<~RUBY
-        # shareable_constant_value: literal
-        C = { foo: 1 }
-      RUBY
-
-      assert_location(ShareableConstantNode, source, 36...50)
-    end
-
     def test_SingletonClassNode
       assert_location(SingletonClassNode, "class << self; end")
     end
@@ -924,7 +915,8 @@ module Prism
 
     def assert_location(kind, source, expected = 0...source.length, **options)
       result = Prism.parse(source, **options)
-      assert result.success?
+      assert_equal [], result.comments
+      assert_equal [], result.errors
 
       node = result.value.statements.body.last
       node = yield node if block_given?
diff --git a/test/prism/snapshots/dstring.txt b/test/prism/snapshots/dstring.txt
index ad395f8a..a24eaf19 100644
--- a/test/prism/snapshots/dstring.txt
+++ b/test/prism/snapshots/dstring.txt
@@ -1,83 +1,11 @@
-@ ProgramNode (location: (1,0)-(29,1))
+@ ProgramNode (location: (1,0)-(2,6))
 ├── locals: []
 └── statements:
-    @ StatementsNode (location: (1,0)-(29,1))
-    └── body: (length: 8)
-        ├── @ StringNode (location: (1,0)-(2,6))
-        │   ├── flags: ∅
-        │   ├── opening_loc: (1,0)-(1,1) = "\""
-        │   ├── content_loc: (1,1)-(2,5) = "foo\n  bar"
-        │   ├── closing_loc: (2,5)-(2,6) = "\""
-        │   └── unescaped: "foo\n  bar"
-        ├── @ InterpolatedStringNode (location: (4,0)-(5,9))
-        │   ├── opening_loc: (4,0)-(4,1) = "\""
-        │   ├── parts: (length: 2)
-        │   │   ├── @ StringNode (location: (4,1)-(5,2))
-        │   │   │   ├── flags: ∅
-        │   │   │   ├── opening_loc: ∅
-        │   │   │   ├── content_loc: (4,1)-(5,2) = "foo\n  "
-        │   │   │   ├── closing_loc: ∅
-        │   │   │   └── unescaped: "foo\n  "
-        │   │   └── @ EmbeddedStatementsNode (location: (5,2)-(5,8))
-        │   │       ├── opening_loc: (5,2)-(5,4) = "\#{"
-        │   │       ├── statements:
-        │   │       │   @ StatementsNode (location: (5,4)-(5,7))
-        │   │       │   └── body: (length: 1)
-        │   │       │       └── @ CallNode (location: (5,4)-(5,7))
-        │   │       │           ├── flags: variable_call, ignore_visibility
-        │   │       │           ├── receiver: ∅
-        │   │       │           ├── call_operator_loc: ∅
-        │   │       │           ├── name: :bar
-        │   │       │           ├── message_loc: (5,4)-(5,7) = "bar"
-        │   │       │           ├── opening_loc: ∅
-        │   │       │           ├── arguments: ∅
-        │   │       │           ├── closing_loc: ∅
-        │   │       │           └── block: ∅
-        │   │       └── closing_loc: (5,7)-(5,8) = "}"
-        │   └── closing_loc: (5,8)-(5,9) = "\""
-        ├── @ InterpolatedStringNode (location: (7,0)-(9,2))
-        │   ├── opening_loc: ∅
-        │   ├── parts: (length: 2)
-        │   │   ├── @ StringNode (location: (7,0)-(8,2))
-        │   │   │   ├── flags: ∅
-        │   │   │   ├── opening_loc: (7,0)-(7,1) = "\""
-        │   │   │   ├── content_loc: (7,1)-(8,1) = "fo\no"
-        │   │   │   ├── closing_loc: (8,1)-(8,2) = "\""
-        │   │   │   └── unescaped: "fo\no"
-        │   │   └── @ StringNode (location: (8,3)-(9,2))
-        │   │       ├── flags: ∅
-        │   │       ├── opening_loc: (8,3)-(8,4) = "\""
-        │   │       ├── content_loc: (8,4)-(9,1) = "ba\nr"
-        │   │       ├── closing_loc: (9,1)-(9,2) = "\""
-        │   │       └── unescaped: "ba\nr"
-        │   └── closing_loc: ∅
-        ├── @ StringNode (location: (11,0)-(13,1))
-        │   ├── flags: ∅
-        │   ├── opening_loc: (11,0)-(11,1) = "\""
-        │   ├── content_loc: (11,1)-(13,0) = "\nfoo\\\n"
-        │   ├── closing_loc: (13,0)-(13,1) = "\""
-        │   └── unescaped: "\nfoo"
-        ├── @ StringNode (location: (15,0)-(17,1))
-        │   ├── flags: ∅
-        │   ├── opening_loc: (15,0)-(15,1) = "\""
-        │   ├── content_loc: (15,1)-(17,0) = "\nfoo\\\\\n"
-        │   ├── closing_loc: (17,0)-(17,1) = "\""
-        │   └── unescaped: "\nfoo\\\n"
-        ├── @ StringNode (location: (19,0)-(21,1))
-        │   ├── flags: ∅
-        │   ├── opening_loc: (19,0)-(19,1) = "\""
-        │   ├── content_loc: (19,1)-(21,0) = "\nfoo\\\\\\\n"
-        │   ├── closing_loc: (21,0)-(21,1) = "\""
-        │   └── unescaped: "\nfoo\\"
-        ├── @ StringNode (location: (23,0)-(25,1))
-        │   ├── flags: ∅
-        │   ├── opening_loc: (23,0)-(23,1) = "\""
-        │   ├── content_loc: (23,1)-(25,0) = "\nfoo\\\\\\\\\n"
-        │   ├── closing_loc: (25,0)-(25,1) = "\""
-        │   └── unescaped: "\nfoo\\\\\n"
-        └── @ StringNode (location: (27,0)-(29,1))
+    @ StatementsNode (location: (1,0)-(2,6))
+    └── body: (length: 1)
+        └── @ StringNode (location: (1,0)-(2,6))
             ├── flags: ∅
-            ├── opening_loc: (27,0)-(27,1) = "\""
-            ├── content_loc: (27,1)-(29,0) = "\nfoo\\\\\\\\\\\n"
-            ├── closing_loc: (29,0)-(29,1) = "\""
-            └── unescaped: "\nfoo\\\\"
+            ├── opening_loc: (1,0)-(1,1) = "\""
+            ├── content_loc: (1,1)-(2,5) = "foo\n  bar"
+            ├── closing_loc: (2,5)-(2,6) = "\""
+            └── unescaped: "foo\n  bar"
diff --git a/test/prism/snapshots/keyword_method_names.txt b/test/prism/snapshots/keyword_method_names.txt
index 9eb04280..6d59790b 100644
--- a/test/prism/snapshots/keyword_method_names.txt
+++ b/test/prism/snapshots/keyword_method_names.txt
@@ -132,6 +132,7 @@
         │   ├── name_loc: (22,13)-(22,14) = "a"
         │   ├── receiver:
         │   │   @ SourceFileNode (location: (22,4)-(22,12))
+        │   │   ├── flags: ∅
         │   │   └── filepath: "keyword_method_names.txt"
         │   ├── parameters: ∅
         │   ├── body: ∅
diff --git a/test/prism/snapshots/keywords.txt b/test/prism/snapshots/keywords.txt
index 6df11487..8a93c38b 100644
--- a/test/prism/snapshots/keywords.txt
+++ b/test/prism/snapshots/keywords.txt
@@ -8,5 +8,6 @@
         ├── @ SelfNode (location: (5,0)-(5,4))
         ├── @ SourceEncodingNode (location: (7,0)-(7,12))
         ├── @ SourceFileNode (location: (9,0)-(9,8))
+        │   ├── flags: ∅
         │   └── filepath: "keywords.txt"
         └── @ SourceLineNode (location: (11,0)-(11,8))
diff --git a/test/prism/snapshots/patterns.txt b/test/prism/snapshots/patterns.txt
index 4efd3159..5662129d 100644
--- a/test/prism/snapshots/patterns.txt
+++ b/test/prism/snapshots/patterns.txt
@@ -445,6 +445,7 @@
         │   │   └── block: ∅
         │   ├── pattern:
         │   │   @ SourceFileNode (location: (23,7)-(23,15))
+        │   │   ├── flags: ∅
         │   │   └── filepath: "patterns.txt"
         │   └── operator_loc: (23,4)-(23,6) = "=>"
         ├── @ MatchRequiredNode (location: (24,0)-(24,15))
@@ -1153,9 +1154,11 @@
         │   │   ├── flags: ∅
         │   │   ├── left:
         │   │   │   @ SourceFileNode (location: (49,7)-(49,15))
+        │   │   │   ├── flags: ∅
         │   │   │   └── filepath: "patterns.txt"
         │   │   ├── right:
         │   │   │   @ SourceFileNode (location: (49,19)-(49,27))
+        │   │   │   ├── flags: ∅
         │   │   │   └── filepath: "patterns.txt"
         │   │   └── operator_loc: (49,16)-(49,18) = ".."
         │   └── operator_loc: (49,4)-(49,6) = "=>"
@@ -2823,6 +2826,7 @@
         │   │   └── block: ∅
         │   ├── pattern:
         │   │   @ SourceFileNode (location: (126,7)-(126,15))
+        │   │   ├── flags: ∅
         │   │   └── filepath: "patterns.txt"
         │   └── operator_loc: (126,4)-(126,6) = "in"
         ├── @ MatchPredicateNode (location: (127,0)-(127,15))
@@ -3504,6 +3508,7 @@
         │   │   └── @ InNode (location: (157,10)-(157,26))
         │   │       ├── pattern:
         │   │       │   @ SourceFileNode (location: (157,13)-(157,21))
+        │   │       │   ├── flags: ∅
         │   │       │   └── filepath: "patterns.txt"
         │   │       ├── statements: ∅
         │   │       ├── in_loc: (157,10)-(157,12) = "in"
@@ -4460,6 +4465,7 @@
         │   │       │   │   @ StatementsNode (location: (184,13)-(184,21))
         │   │       │   │   └── body: (length: 1)
         │   │       │   │       └── @ SourceFileNode (location: (184,13)-(184,21))
+        │   │       │   │           ├── flags: ∅
         │   │       │   │           └── filepath: "patterns.txt"
         │   │       │   ├── consequent: ∅
         │   │       │   └── end_keyword_loc: ∅
diff --git a/test/prism/snapshots/unparser/corpus/literal/pragma.txt b/test/prism/snapshots/unparser/corpus/literal/pragma.txt
index ade81bc8..08e386b8 100644
--- a/test/prism/snapshots/unparser/corpus/literal/pragma.txt
+++ b/test/prism/snapshots/unparser/corpus/literal/pragma.txt
@@ -5,6 +5,7 @@
     └── body: (length: 4)
         ├── @ SourceEncodingNode (location: (1,0)-(1,12))
         ├── @ SourceFileNode (location: (2,0)-(2,8))
+        │   ├── flags: ∅
         │   └── filepath: "unparser/corpus/literal/pragma.txt"
         ├── @ SourceLineNode (location: (3,0)-(3,8))
         └── @ CallNode (location: (4,0)-(4,7))
diff --git a/test/prism/snapshots/whitequark/pattern_matching__FILE__LINE_literals.txt b/test/prism/snapshots/whitequark/pattern_matching__FILE__LINE_literals.txt
index 48f377cc..6f315780 100644
--- a/test/prism/snapshots/whitequark/pattern_matching__FILE__LINE_literals.txt
+++ b/test/prism/snapshots/whitequark/pattern_matching__FILE__LINE_literals.txt
@@ -9,6 +9,7 @@
             │   ├── flags: ∅
             │   ├── elements: (length: 3)
             │   │   ├── @ SourceFileNode (location: (1,14)-(1,22))
+            │   │   │   ├── flags: ∅
             │   │   │   └── filepath: "whitequark/pattern_matching__FILE__LINE_literals.txt"
             │   │   ├── @ CallNode (location: (1,24)-(1,36))
             │   │   │   ├── flags: ∅
@@ -37,6 +38,7 @@
             │       │   ├── constant: ∅
             │       │   ├── requireds: (length: 3)
             │       │   │   ├── @ SourceFileNode (location: (2,14)-(2,22))
+            │       │   │   │   ├── flags: ∅
             │       │   │   │   └── filepath: "whitequark/pattern_matching__FILE__LINE_literals.txt"
             │       │   │   ├── @ SourceLineNode (location: (2,24)-(2,32))
             │       │   │   └── @ SourceEncodingNode (location: (2,34)-(2,46))
diff --git a/test/prism/snapshots/whitequark/string___FILE__.txt b/test/prism/snapshots/whitequark/string___FILE__.txt
index c6ce21be..a12499a6 100644
--- a/test/prism/snapshots/whitequark/string___FILE__.txt
+++ b/test/prism/snapshots/whitequark/string___FILE__.txt
@@ -4,4 +4,5 @@
     @ StatementsNode (location: (1,0)-(1,8))
     └── body: (length: 1)
         └── @ SourceFileNode (location: (1,0)-(1,8))
+            ├── flags: ∅
             └── filepath: "whitequark/string___FILE__.txt"
diff --git a/test/prism/static_inspect_test.rb b/test/prism/static_inspect_test.rb
index 07b7ac32..41301693 100644
--- a/test/prism/static_inspect_test.rb
+++ b/test/prism/static_inspect_test.rb
@@ -58,7 +58,7 @@ module Prism
     end
 
     def test_source_file
-      assert_equal __FILE__.inspect, static_inspect("__FILE__", filepath: __FILE__)
+      assert_equal __FILE__.inspect, static_inspect("__FILE__", filepath: __FILE__, frozen_string_literal: true)
     end
 
     def test_source_line
diff --git a/test/prism/static_literals_test.rb b/test/prism/static_literals_test.rb
index 4e98c157..26699319 100644
--- a/test/prism/static_literals_test.rb
+++ b/test/prism/static_literals_test.rb
@@ -34,7 +34,6 @@ module Prism
 
       assert_warning("\"#{__FILE__}\"")
       assert_warning("\"foo\"")
-      assert_warning("\"#{__FILE__}\"", "__FILE__")
 
       assert_warning("/foo/")