Repository: ruby/prism
Pull request #1712 (2023-10-18 16:31:23)

Exclude comments when only serializing semantic fields
I don't think there is any value to have comments serialized for the Java Loader, it's just making the serialized size bigger.
Before:
```
be rake serialized_size:topgems
Total sizes for top 100 gems:
total source size:      90207647
total serialized size:  56131852
total serialized/total source: 0.622

Stats of ratio serialized/source per file:
average: 0.745
median:  0.724
1st quartile: 0.537
3rd quartile: 0.924
min - max: 0.036 - 3.532
```
After:
```
be rake serialized_size:topgems
Total sizes for top 100 gems:
total source size:      90207647
total serialized size:  53065393
total serialized/total source: 0.588

Stats of ratio serialized/source per file:
average: 0.716
median:  0.702
1st quartile: 0.496
3rd quartile: 0.913
min - max: 0.019 - 3.519
```

So that's quite a big saving in serialized size.

cc @enebo 


Patch:
diff --git a/include/prism/util/pm_constant_pool.h b/include/prism/util/pm_constant_pool.h
index defd6ad2..3ea335ac 100644
--- a/include/prism/util/pm_constant_pool.h
+++ b/include/prism/util/pm_constant_pool.h
@@ -39,21 +39,9 @@ size_t pm_constant_id_list_memsize(pm_constant_id_list_t *list);
 // Free the memory associated with a list of constant ids.
 void pm_constant_id_list_free(pm_constant_id_list_t *list);
 
-// Constant pool buckets can have a couple of different types.
-typedef unsigned int pm_constant_pool_bucket_type_t;
-
-// By default, each constant is a slice of the source.
-static const pm_constant_pool_bucket_type_t PM_CONSTANT_POOL_BUCKET_DEFAULT = 0;
-
-// An owned constant is one for which memory has been allocated.
-static const pm_constant_pool_bucket_type_t PM_CONSTANT_POOL_BUCKET_OWNED = 1;
-
-// A constant constant is known at compile time.
-static const pm_constant_pool_bucket_type_t PM_CONSTANT_POOL_BUCKET_CONSTANT = 2;
-
 typedef struct {
-    unsigned int id: 30;
-    pm_constant_pool_bucket_type_t type: 2;
+    unsigned int id: 31;
+    bool owned: 1;
     uint32_t hash;
 } pm_constant_pool_bucket_t;
 
@@ -75,8 +63,10 @@ typedef struct {
 // Initialize a new constant pool with a given capacity.
 bool pm_constant_pool_init(pm_constant_pool_t *pool, uint32_t capacity);
 
-// Return a pointer to the constant indicated by the given constant id.
-pm_constant_t * pm_constant_pool_id_to_constant(pm_constant_pool_t *pool, pm_constant_id_t constant_id);
+static inline pm_constant_t* pm_constant_pool_id_to_constant(pm_constant_pool_t *pool, pm_constant_id_t constant_id) {
+    assert(constant_id > 0 && constant_id <= pool->size);
+    return &pool->constants[constant_id - 1];
+}
 
 // Insert a constant into a constant pool that is a slice of a source string.
 // Returns the id of the constant, or 0 if any potential calls to resize fail.
@@ -87,10 +77,6 @@ pm_constant_id_t pm_constant_pool_insert_shared(pm_constant_pool_t *pool, const
 // resize fail.
 pm_constant_id_t pm_constant_pool_insert_owned(pm_constant_pool_t *pool, const uint8_t *start, size_t length);
 
-// Insert a constant into a constant pool from memory that is constant. Returns
-// the id of the constant, or 0 if any potential calls to resize fail.
-pm_constant_id_t pm_constant_pool_insert_constant(pm_constant_pool_t *pool, const uint8_t *start, size_t length);
-
 // Free the memory associated with a constant pool.
 void pm_constant_pool_free(pm_constant_pool_t *pool);
 
diff --git a/java/org/prism/ParseResult.java b/java/org/prism/ParseResult.java
index fef4a32d..6470dbaf 100644
--- a/java/org/prism/ParseResult.java
+++ b/java/org/prism/ParseResult.java
@@ -2,27 +2,6 @@ package org.prism;
 
 public final class ParseResult {
 
-    public enum CommentType {
-        /** # comment */
-        INLINE,
-        /** =begin/=end */
-        EMBEDDED_DOCUMENT,
-        /** after __END__ */
-        __END__;
-
-        static final CommentType[] VALUES = values();
-    }
-
-    public static final class Comment {
-        public final CommentType type;
-        public final Nodes.Location location;
-
-        public Comment(CommentType type, Nodes.Location location) {
-            this.type = type;
-            this.location = location;
-        }
-    }
-
     public static final class MagicComment {
         public final Nodes.Location keyLocation;
         public final Nodes.Location valueLocation;
@@ -54,14 +33,12 @@ public final class ParseResult {
     }
 
     public final Nodes.Node value;
-    public final Comment[] comments;
     public final MagicComment[] magicComments;
     public final Error[] errors;
     public final Warning[] warnings;
 
-    public ParseResult(Nodes.Node value, Comment[] comments, MagicComment[] magicComments, Error[] errors, Warning[] warnings) {
+    public ParseResult(Nodes.Node value, MagicComment[] magicComments, Error[] errors, Warning[] warnings) {
         this.value = value;
-        this.comments = comments;
         this.magicComments = magicComments;
         this.errors = errors;
         this.warnings = warnings;
diff --git a/lib/prism/debug.rb b/lib/prism/debug.rb
index 6a68a3d3..9c6756ff 100644
--- a/lib/prism/debug.rb
+++ b/lib/prism/debug.rb
@@ -45,16 +45,29 @@ module Prism
     # For the given source, compiles with CRuby and returns a list of all of the
     # sets of local variables that were encountered.
     def self.cruby_locals(source)
-      verbose, $VERBOSE = $VERBOSE, nil
+      verbose = $VERBOSE
+      $VERBOSE = nil
 
       begin
         locals = []
         stack = [ISeq.new(RubyVM::InstructionSequence.compile(source).to_a)]
 
         while (iseq = stack.pop)
-          # For some reason, CRuby occasionally pushes this special local
-          # variable when there are splat arguments. We get rid of that here.
-          locals << (iseq.local_table - [:"#arg_rest"])
+          if iseq.type != :once
+            names = iseq.local_table
+
+            # CRuby will push on a special local variable when there are keyword
+            # arguments. We get rid of that here.
+            names = names.grep_v(Integer)
+
+            # For some reason, CRuby occasionally pushes this special local
+            # variable when there are splat arguments. We get rid of that here.
+            names = names.grep_v(:"#arg_rest")
+
+            # Now push them onto the list of locals.
+            locals << names
+          end
+
           iseq.each_child { |child| stack << child }
         end
 
@@ -64,8 +77,6 @@ module Prism
       end
     end
 
-    AnonymousLocal = Object.new
-
     # For the given source, parses with prism and returns a list of all of the
     # sets of local variables that were encountered.
     def self.prism_locals(source)
@@ -86,27 +97,20 @@ module Prism
           # order here so that we can compare properly.
           if params
             sorted = [
-              *params.requireds.map do |required|
-                if required.is_a?(RequiredParameterNode)
-                  required.name
-                else
-                  AnonymousLocal
-                end
-              end,
+              *params.requireds.grep(RequiredParameterNode).map(&:name),
               *params.optionals.map(&:name),
               *((params.rest.name || :*) if params.rest && params.rest.operator != ","),
-              *params.posts.map do |post|
-                if post.is_a?(RequiredParameterNode)
-                  post.name
-                else
-                  AnonymousLocal
-                end
-              end,
+              *params.posts.grep(RequiredParameterNode).map(&:name),
               *params.keywords.reject(&:value).map(&:name),
               *params.keywords.select(&:value).map(&:name)
             ]
 
-            sorted << AnonymousLocal if params.keywords.any?
+            # TODO: When we get a ... parameter, we should be pushing * and &
+            # onto the local list. We don't do that yet, so we need to add them
+            # in here.
+            if params.keyword_rest.is_a?(ForwardingParameterNode)
+              sorted.push(:*, :&, :"...")
+            end
 
             # Recurse down the parameter tree to find any destructured
             # parameters and add them after the other parameters.
@@ -125,19 +129,11 @@ module Prism
             names = sorted.concat(names - sorted)
           end
 
-          names.map!.with_index do |name, index|
-            if name == AnonymousLocal
-              names.length - index + 1
-            else
-              name
-            end
-          end
-
           locals << names
         when ClassNode, ModuleNode, ProgramNode, SingletonClassNode
           locals << node.locals
         when ForNode
-          locals << [2]
+          locals << []
         when PostExecutionNode
           locals.push([], [])
         when InterpolatedRegularExpressionNode
diff --git a/lib/prism/lex_compat.rb b/lib/prism/lex_compat.rb
index 4801fe36..a17d4eaa 100644
--- a/lib/prism/lex_compat.rb
+++ b/lib/prism/lex_compat.rb
@@ -357,7 +357,6 @@ module Prism
           @dedent_next = true
           @dedent = nil
           @embexpr_balance = 0
-          @ended_on_newline = false
         end
 
         # As tokens are coming in, we track the minimum amount of common leading
@@ -367,14 +366,13 @@ module Prism
           case token.event
           when :on_embexpr_beg, :on_heredoc_beg
             @embexpr_balance += 1
-            @dedent = 0 if @dedent_next && @ended_on_newline
           when :on_embexpr_end, :on_heredoc_end
             @embexpr_balance -= 1
           when :on_tstring_content
             if embexpr_balance == 0
               line = token.value
 
-              if dedent_next && !(line.strip.empty? && line.end_with?("\n"))
+              if !(line.strip.empty? && line.end_with?("\n")) && dedent_next
                 leading = line[/\A(\s*)\n?/, 1]
                 next_dedent = 0
 
@@ -387,16 +385,11 @@ module Prism
                 end
 
                 @dedent = [dedent, next_dedent].compact.min
-                @dedent_next = true
-                @ended_on_newline = line.end_with?("\n")
-                tokens << token
-                return
               end
             end
           end
 
           @dedent_next = token.event == :on_tstring_content && embexpr_balance == 0
-          @ended_on_newline = false
           tokens << token
         end
 
diff --git a/src/prism.c b/src/prism.c
index 2bef8e3e..fbf9d3c7 100644
--- a/src/prism.c
+++ b/src/prism.c
@@ -496,8 +496,18 @@ pm_parser_constant_id_owned(pm_parser_t *parser, const uint8_t *start, size_t le
 
 // Retrieve the constant pool id for the given static literal C string.
 static inline pm_constant_id_t
-pm_parser_constant_id_constant(pm_parser_t *parser, const char *start, size_t length) {
-    return pm_constant_pool_insert_constant(&parser->constant_pool, (const uint8_t *) start, length);
+pm_parser_constant_id_static(pm_parser_t *parser, const char *start, size_t length) {
+    uint8_t *owned_copy;
+    if (length > 0) {
+        owned_copy = malloc(length);
+        memcpy(owned_copy, start, length);
+    } else {
+        owned_copy = malloc(1);
+        owned_copy[0] = '\0';
+    }
+    return pm_constant_pool_insert_owned(&parser->constant_pool, owned_copy, length);
+    // Does not work because the static literal cannot be serialized as an offset of source
+    // return pm_constant_pool_insert_shared(&parser->constant_pool, start, length);
 }
 
 // Retrieve the constant pool id for the given token.
@@ -1448,7 +1458,7 @@ pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_
     node->closing_loc = arguments->closing_loc;
     node->block = arguments->block;
 
-    node->name = pm_parser_constant_id_constant(parser, "[]", 2);
+    node->name = pm_parser_constant_id_static(parser, "[]", 2);
     return node;
 }
 
@@ -1548,7 +1558,7 @@ pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *me
     node->arguments = arguments->arguments;
     node->closing_loc = arguments->closing_loc;
 
-    node->name = pm_parser_constant_id_constant(parser, "!", 1);
+    node->name = pm_parser_constant_id_static(parser, "!", 1);
     return node;
 }
 
@@ -1575,7 +1585,7 @@ pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token
         node->base.flags |= PM_CALL_NODE_FLAGS_SAFE_NAVIGATION;
     }
 
-    node->name = pm_parser_constant_id_constant(parser, "call", 4);
+    node->name = pm_parser_constant_id_static(parser, "call", 4);
     return node;
 }
 
@@ -1590,7 +1600,7 @@ pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *
     node->receiver = receiver;
     node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
 
-    node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
+    node->name = pm_parser_constant_id_static(parser, name, strlen(name));
     return node;
 }
 
@@ -1644,8 +1654,7 @@ pm_call_node_writable_p(pm_call_node_t *node) {
 static void
 pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
     pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
-
-    if (write_constant->length > 0) {
+    if (write_constant->length >= 1) {
         size_t length = write_constant->length - 1;
 
         void *memory = malloc(length);
@@ -1654,7 +1663,7 @@ pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, p
         *read_name = pm_constant_pool_insert_owned(&parser->constant_pool, (uint8_t *) memory, length);
     } else {
         // We can get here if the message was missing because of a syntax error.
-        *read_name = pm_parser_constant_id_constant(parser, "", 0);
+        *read_name = pm_parser_constant_id_static(parser, "", 0);
     }
 }
 
@@ -5101,13 +5110,6 @@ pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id) {
     }
 }
 
-// Add a local variable from a constant string to the current scope.
-static inline void
-pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
-    pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
-    if (constant_id != 0) pm_parser_local_add(parser, constant_id);
-}
-
 // Add a local variable from a location to the current scope.
 static pm_constant_id_t
 pm_parser_local_add_location(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
@@ -9637,7 +9639,7 @@ parse_target(pm_parser_t *parser, pm_node_t *target) {
                 (call->block == NULL)
             ) {
                 // Replace the name with "[]=".
-                call->name = pm_parser_constant_id_constant(parser, "[]=", 3);
+                call->name = pm_parser_constant_id_static(parser, "[]=", 3);
                 return target;
             }
         }
@@ -9804,7 +9806,7 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
                 target->location.end = value->location.end;
 
                 // Replace the name with "[]=".
-                call->name = pm_parser_constant_id_constant(parser, "[]=", 3);
+                call->name = pm_parser_constant_id_static(parser, "[]=", 3);
                 return target;
             }
 
@@ -10425,17 +10427,11 @@ parse_parameters(
                 if (!allows_forwarding_parameter) {
                     pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
                 }
-
                 if (order > PM_PARAMETERS_ORDER_NOTHING_AFTER) {
                     update_parameter_state(parser, &parser->current, &order);
                     parser_lex(parser);
 
-                    if (allows_forwarding_parameter) {
-                        pm_parser_local_add_constant(parser, "*", 1);
-                        pm_parser_local_add_constant(parser, "&", 1);
-                        pm_parser_local_add_token(parser, &parser->previous);
-                    }
-
+                    pm_parser_local_add_token(parser, &parser->previous);
                     pm_forwarding_parameter_node_t *param = pm_forwarding_parameter_node_create(parser, &parser->previous);
                     if (params->keyword_rest != NULL) {
                         // If we already have a keyword rest parameter, then we replace it with the
@@ -10450,7 +10446,6 @@ parse_parameters(
                     update_parameter_state(parser, &parser->current, &order);
                     parser_lex(parser);
                 }
-
                 break;
             }
             case PM_TOKEN_CLASS_VARIABLE:
diff --git a/src/util/pm_constant_pool.c b/src/util/pm_constant_pool.c
index 63dd86a8..d2c4f1e1 100644
--- a/src/util/pm_constant_pool.c
+++ b/src/util/pm_constant_pool.c
@@ -154,16 +154,9 @@ pm_constant_pool_init(pm_constant_pool_t *pool, uint32_t capacity) {
     return true;
 }
 
-// Return a pointer to the constant indicated by the given constant id.
-pm_constant_t *
-pm_constant_pool_id_to_constant(pm_constant_pool_t *pool, pm_constant_id_t constant_id) {
-    assert(constant_id > 0 && constant_id <= pool->size);
-    return &pool->constants[constant_id - 1];
-}
-
 // Insert a constant into a constant pool and return its index in the pool.
 static inline pm_constant_id_t
-pm_constant_pool_insert(pm_constant_pool_t *pool, const uint8_t *start, size_t length, pm_constant_pool_bucket_type_t type) {
+pm_constant_pool_insert(pm_constant_pool_t *pool, const uint8_t *start, size_t length, bool owned) {
     if (pool->size >= (pool->capacity / 4 * 3)) {
         if (!pm_constant_pool_resize(pool)) return 0;
     }
@@ -185,19 +178,19 @@ pm_constant_pool_insert(pm_constant_pool_t *pool, const uint8_t *start, size_t l
             // Since we have found a match, we need to check if this is
             // attempting to insert a shared or an owned constant. We want to
             // prefer shared constants since they don't require allocations.
-            if (type == PM_CONSTANT_POOL_BUCKET_OWNED) {
+            if (owned) {
                 // If we're attempting to insert an owned constant and we have
                 // an existing constant, then either way we don't want the given
                 // memory. Either it's duplicated with the existing constant or
                 // it's not necessary because we have a shared version.
                 free((void *) start);
-            } else if (bucket->type == PM_CONSTANT_POOL_BUCKET_OWNED) {
+            } else if (bucket->owned) {
                 // If we're attempting to insert a shared constant and the
                 // existing constant is owned, then we can free the owned
                 // constant and replace it with the shared constant.
                 free((void *) constant->start);
                 constant->start = start;
-                bucket->type = PM_CONSTANT_POOL_BUCKET_DEFAULT;
+                bucket->owned = false;
             }
 
             return bucket->id;
@@ -209,15 +202,15 @@ pm_constant_pool_insert(pm_constant_pool_t *pool, const uint8_t *start, size_t l
     // IDs are allocated starting at 1, since the value 0 denotes a non-existant
     // constant.
     uint32_t id = ++pool->size;
-    assert(pool->size < ((uint32_t) (1 << 30)));
+    assert(pool->size < ((uint32_t) (1 << 31)));
 
     *bucket = (pm_constant_pool_bucket_t) {
-        .id = (unsigned int) (id & 0x3fffffff),
-        .type = (unsigned int) (type & 0x3),
+        .id = (unsigned int) (id & 0x7FFFFFFF),
+        .owned = owned,
         .hash = hash
     };
 
-    pool->constants[id - 1] = (pm_constant_t) {
+    pool->constants[id - 1]  = (pm_constant_t) {
         .start = start,
         .length = length,
     };
@@ -229,7 +222,7 @@ pm_constant_pool_insert(pm_constant_pool_t *pool, const uint8_t *start, size_t l
 // if any potential calls to resize fail.
 pm_constant_id_t
 pm_constant_pool_insert_shared(pm_constant_pool_t *pool, const uint8_t *start, size_t length) {
-    return pm_constant_pool_insert(pool, start, length, PM_CONSTANT_POOL_BUCKET_DEFAULT);
+    return pm_constant_pool_insert(pool, start, length, false);
 }
 
 // Insert a constant into a constant pool from memory that is now owned by the
@@ -237,14 +230,7 @@ pm_constant_pool_insert_shared(pm_constant_pool_t *pool, const uint8_t *start, s
 // resize fail.
 pm_constant_id_t
 pm_constant_pool_insert_owned(pm_constant_pool_t *pool, const uint8_t *start, size_t length) {
-    return pm_constant_pool_insert(pool, start, length, PM_CONSTANT_POOL_BUCKET_OWNED);
-}
-
-// Insert a constant into a constant pool from memory that is constant. Returns
-// the id of the constant, or 0 if any potential calls to resize fail.
-pm_constant_id_t
-pm_constant_pool_insert_constant(pm_constant_pool_t *pool, const uint8_t *start, size_t length) {
-    return pm_constant_pool_insert(pool, start, length, PM_CONSTANT_POOL_BUCKET_CONSTANT);
+    return pm_constant_pool_insert(pool, start, length, true);
 }
 
 // Free the memory associated with a constant pool.
@@ -256,7 +242,7 @@ pm_constant_pool_free(pm_constant_pool_t *pool) {
         pm_constant_pool_bucket_t *bucket = &pool->buckets[index];
 
         // If an id is set on this constant, then we know we have content here.
-        if (bucket->id != 0 && bucket->type == PM_CONSTANT_POOL_BUCKET_OWNED) {
+        if (bucket->id != 0 && bucket->owned) {
             pm_constant_t *constant = &pool->constants[bucket->id - 1];
             free((void *) constant->start);
         }
diff --git a/templates/java/org/prism/Loader.java.erb b/templates/java/org/prism/Loader.java.erb
index 58297432..f97d38d9 100644
--- a/templates/java/org/prism/Loader.java.erb
+++ b/templates/java/org/prism/Loader.java.erb
@@ -108,7 +108,6 @@ public class Loader {
         this.encodingName = new String(encodingNameBytes, StandardCharsets.US_ASCII);
         this.encodingCharset = getEncodingCharset(this.encodingName);
 
-        ParseResult.Comment[] comments = loadComments();
         ParseResult.MagicComment[] magicComments = loadMagicComments();
         ParseResult.Error[] errors = loadSyntaxErrors();
         ParseResult.Warning[] warnings = loadWarnings();
@@ -128,7 +127,7 @@ public class Loader {
         MarkNewlinesVisitor visitor = new MarkNewlinesVisitor(source, newlineMarked);
         node.accept(visitor);
 
-        return new ParseResult(node, comments, magicComments, errors, warnings);
+        return new ParseResult(node, magicComments, errors, warnings);
     }
 
     private byte[] loadEmbeddedString() {
@@ -153,21 +152,6 @@ public class Loader {
         }
     }
 
-    private ParseResult.Comment[] loadComments() {
-        int count = loadVarInt();
-        ParseResult.Comment[] comments = new ParseResult.Comment[count];
-
-        for (int i = 0; i < count; i++) {
-            ParseResult.CommentType type = ParseResult.CommentType.VALUES[buffer.get()];
-            Nodes.Location location = loadLocation();
-
-            ParseResult.Comment comment = new ParseResult.Comment(type, location);
-            comments[i] = comment;
-        }
-
-        return comments;
-    }
-
     private ParseResult.MagicComment[] loadMagicComments() {
         int count = loadVarInt();
         ParseResult.MagicComment[] magicComments = new ParseResult.MagicComment[count];
diff --git a/templates/src/serialize.c.erb b/templates/src/serialize.c.erb
index 006fae6f..22824835 100644
--- a/templates/src/serialize.c.erb
+++ b/templates/src/serialize.c.erb
@@ -200,7 +200,9 @@ pm_serialize_encoding(pm_encoding_t *encoding, pm_buffer_t *buffer) {
 void
 pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
     pm_serialize_encoding(&parser->encoding, buffer);
+<%- unless Prism::SERIALIZE_ONLY_SEMANTICS_FIELDS -%>
     pm_serialize_comment_list(parser, &parser->comment_list, buffer);
+<%- end -%>
     pm_serialize_magic_comment_list(parser, &parser->magic_comment_list, buffer);
     pm_serialize_diagnostic_list(parser, &parser->error_list, buffer);
     pm_serialize_diagnostic_list(parser, &parser->warning_list, buffer);
@@ -234,12 +236,12 @@ pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer)
             pm_constant_t *constant = &parser->constant_pool.constants[bucket->id - 1];
             size_t buffer_offset = offset + ((((size_t)bucket->id) - 1) * 8);
 
-            if (bucket->type == PM_CONSTANT_POOL_BUCKET_OWNED || bucket->type == PM_CONSTANT_POOL_BUCKET_CONSTANT) {
-                // Since this is an owned or constant constant, we are going to
-                // write its contents into the buffer after the constant pool.
-                // So effectively in place of the source offset, we have a
-                // buffer offset. We will add a leading 1 to indicate that this
-                // is a buffer offset.
+            if (bucket->owned) {
+                // Since this is an owned constant, we are going to write its
+                // contents into the buffer after the constant pool. So
+                // effectively in place of the source offset, we have a buffer
+                // offset. We will add a leading 1 to indicate that this is a
+                // buffer offset.
                 uint32_t content_offset = pm_sizet_to_u32(buffer->length);
                 uint32_t owned_mask = (uint32_t) (1 << 31);
 


Test patch:
diff --git a/test/prism/errors_test.rb b/test/prism/errors_test.rb
index 70fd030a..e043c591 100644
--- a/test/prism/errors_test.rb
+++ b/test/prism/errors_test.rb
@@ -723,7 +723,7 @@ module Prism
           nil
         ),
         nil,
-        [:*, :&, :"...", :a],
+        [:"...", :a],
         Location(),
         nil,
         Location(),
@@ -800,7 +800,7 @@ module Prism
         nil,
         ParametersNode([], [], nil, [], [], ForwardingParameterNode(), nil),
         nil,
-        [:*, :&, :"..."],
+        [:"..."],
         Location(),
         nil,
         Location(),
@@ -987,7 +987,7 @@ module Prism
 
     def test_do_not_allow_forward_arguments_in_lambda_literals
       expected = LambdaNode(
-        [],
+        [:"..."],
         Location(),
         Location(),
         Location(),
@@ -1009,7 +1009,7 @@ module Prism
         nil,
         nil,
         BlockNode(
-          [],
+          [:"..."],
           BlockParametersNode(ParametersNode([], [], nil, [], [], ForwardingParameterNode(), nil), [], Location(), Location()),
           nil,
           Location(),
diff --git a/test/prism/fixtures/tilde_heredocs.txt b/test/prism/fixtures/tilde_heredocs.txt
index cca47ef0..415d4d42 100644
--- a/test/prism/fixtures/tilde_heredocs.txt
+++ b/test/prism/fixtures/tilde_heredocs.txt
@@ -1,9 +1,3 @@
-<<~EOF
-  a
-#{1}
-  a
-EOF
-
 <<~EOF
   a
 EOF
diff --git a/test/prism/heredoc_dedent_test.rb b/test/prism/heredoc_dedent_test.rb
index 9fbc4d93..19432357 100644
--- a/test/prism/heredoc_dedent_test.rb
+++ b/test/prism/heredoc_dedent_test.rb
@@ -7,13 +7,8 @@ module Prism
     filepath = File.expand_path("fixtures/tilde_heredocs.txt", __dir__)
 
     File.read(filepath).split(/(?=\n)\n(?=<)/).each_with_index do |heredoc, index|
-      # The first example in this file has incorrect dedent calculated by
-      # TruffleRuby so we skip it.
-      next if index == 0 && RUBY_ENGINE == "truffleruby"
-
       define_method "test_heredoc_#{index}" do
         node = Prism.parse(heredoc).value.statements.body.first
-
         if node.is_a?(StringNode)
           actual = node.unescaped
         else
diff --git a/test/prism/snapshots/methods.txt b/test/prism/snapshots/methods.txt
index bf681386..73db4ae5 100644
--- a/test/prism/snapshots/methods.txt
+++ b/test/prism/snapshots/methods.txt
@@ -183,7 +183,7 @@
         │   │   │   @ ForwardingParameterNode (location: (19,6)-(19,9))
         │   │   └── block: ∅
         │   ├── body: ∅
-        │   ├── locals: [:*, :&, :"..."]
+        │   ├── locals: [:"..."]
         │   ├── def_keyword_loc: (19,0)-(19,3) = "def"
         │   ├── operator_loc: ∅
         │   ├── lparen_loc: (19,5)-(19,6) = "("
@@ -949,7 +949,7 @@
         │   │           ├── block: ∅
         │   │           ├── flags: ∅
         │   │           └── name: :b
-        │   ├── locals: [:*, :&, :"..."]
+        │   ├── locals: [:"..."]
         │   ├── def_keyword_loc: (112,0)-(112,3) = "def"
         │   ├── operator_loc: ∅
         │   ├── lparen_loc: (112,5)-(112,6) = "("
@@ -990,7 +990,7 @@
         │   │           ├── block: ∅
         │   │           ├── flags: ∅
         │   │           └── name: :b
-        │   ├── locals: [:*, :&, :"..."]
+        │   ├── locals: [:"..."]
         │   ├── def_keyword_loc: (114,0)-(114,3) = "def"
         │   ├── operator_loc: ∅
         │   ├── lparen_loc: (114,5)-(114,6) = "("
@@ -1210,7 +1210,7 @@
         │   │           │       │           └── name: :b
         │   │           │       └── closing_loc: (136,24)-(136,25) = "}"
         │   │           └── closing_loc: (136,25)-(136,26) = "\""
-        │   ├── locals: [:*, :&, :"..."]
+        │   ├── locals: [:"..."]
         │   ├── def_keyword_loc: (136,0)-(136,3) = "def"
         │   ├── operator_loc: ∅
         │   ├── lparen_loc: (136,5)-(136,6) = "("
diff --git a/test/prism/snapshots/seattlerb/defn_arg_forward_args.txt b/test/prism/snapshots/seattlerb/defn_arg_forward_args.txt
index 75990338..7fb3e123 100644
--- a/test/prism/snapshots/seattlerb/defn_arg_forward_args.txt
+++ b/test/prism/snapshots/seattlerb/defn_arg_forward_args.txt
@@ -38,7 +38,7 @@
             │           ├── block: ∅
             │           ├── flags: ∅
             │           └── name: :b
-            ├── locals: [:x, :*, :&, :"..."]
+            ├── locals: [:x, :"..."]
             ├── def_keyword_loc: (1,0)-(1,3) = "def"
             ├── operator_loc: ∅
             ├── lparen_loc: (1,5)-(1,6) = "("
diff --git a/test/prism/snapshots/seattlerb/defn_args_forward_args.txt b/test/prism/snapshots/seattlerb/defn_args_forward_args.txt
index c1f190d5..dfd0b67c 100644
--- a/test/prism/snapshots/seattlerb/defn_args_forward_args.txt
+++ b/test/prism/snapshots/seattlerb/defn_args_forward_args.txt
@@ -47,7 +47,7 @@
             │           ├── block: ∅
             │           ├── flags: ∅
             │           └── name: :b
-            ├── locals: [:x, :y, :z, :*, :&, :"..."]
+            ├── locals: [:x, :y, :z, :"..."]
             ├── def_keyword_loc: (1,0)-(1,3) = "def"
             ├── operator_loc: ∅
             ├── lparen_loc: (1,5)-(1,6) = "("
diff --git a/test/prism/snapshots/seattlerb/defn_forward_args.txt b/test/prism/snapshots/seattlerb/defn_forward_args.txt
index a711515c..4f4bc7cc 100644
--- a/test/prism/snapshots/seattlerb/defn_forward_args.txt
+++ b/test/prism/snapshots/seattlerb/defn_forward_args.txt
@@ -33,7 +33,7 @@
             │           ├── block: ∅
             │           ├── flags: ∅
             │           └── name: :b
-            ├── locals: [:*, :&, :"..."]
+            ├── locals: [:"..."]
             ├── def_keyword_loc: (1,0)-(1,3) = "def"
             ├── operator_loc: ∅
             ├── lparen_loc: (1,5)-(1,6) = "("
diff --git a/test/prism/snapshots/seattlerb/defn_forward_args__no_parens.txt b/test/prism/snapshots/seattlerb/defn_forward_args__no_parens.txt
index db999623..f3eaef61 100644
--- a/test/prism/snapshots/seattlerb/defn_forward_args__no_parens.txt
+++ b/test/prism/snapshots/seattlerb/defn_forward_args__no_parens.txt
@@ -33,7 +33,7 @@
             │           ├── block: ∅
             │           ├── flags: ∅
             │           └── name: :m
-            ├── locals: [:*, :&, :"..."]
+            ├── locals: [:"..."]
             ├── def_keyword_loc: (1,0)-(1,3) = "def"
             ├── operator_loc: ∅
             ├── lparen_loc: ∅
diff --git a/test/prism/snapshots/tilde_heredocs.txt b/test/prism/snapshots/tilde_heredocs.txt
index 3f9ca047..3d333577 100644
--- a/test/prism/snapshots/tilde_heredocs.txt
+++ b/test/prism/snapshots/tilde_heredocs.txt
@@ -1,255 +1,247 @@
-@ ProgramNode (location: (1,0)-(94,6))
+@ ProgramNode (location: (1,0)-(88,6))
 ├── locals: []
 └── statements:
-    @ StatementsNode (location: (1,0)-(94,6))
-    └── body: (length: 19)
-        ├── @ InterpolatedStringNode (location: (1,0)-(1,6))
-        │   ├── opening_loc: (1,0)-(1,6) = "<<~EOF"
-        │   ├── parts: (length: 4)
-        │   │   ├── @ StringNode (location: (2,0)-(2,0))
-        │   │   │   ├── flags: ∅
-        │   │   │   ├── opening_loc: ∅
-        │   │   │   ├── content_loc: (2,0)-(2,0) = "  a\n"
-        │   │   │   ├── closing_loc: ∅
-        │   │   │   └── unescaped: "  a\n"
-        │   │   ├── @ EmbeddedStatementsNode (location: (3,0)-(3,4))
-        │   │   │   ├── opening_loc: (3,0)-(3,2) = "\#{"
-        │   │   │   ├── statements:
-        │   │   │   │   @ StatementsNode (location: (3,2)-(3,3))
-        │   │   │   │   └── body: (length: 1)
-        │   │   │   │       └── @ IntegerNode (location: (3,2)-(3,3))
-        │   │   │   │           └── flags: decimal
-        │   │   │   └── closing_loc: (3,3)-(3,4) = "}"
-        │   │   ├── @ StringNode (location: (3,4)-(3,0))
-        │   │   │   ├── flags: ∅
-        │   │   │   ├── opening_loc: ∅
-        │   │   │   ├── content_loc: (3,4)-(3,0) = "\n"
-        │   │   │   ├── closing_loc: ∅
-        │   │   │   └── unescaped: "\n"
-        │   │   └── @ StringNode (location: (4,0)-(4,0))
-        │   │       ├── flags: ∅
-        │   │       ├── opening_loc: ∅
-        │   │       ├── content_loc: (4,0)-(4,0) = "  a\n"
-        │   │       ├── closing_loc: ∅
-        │   │       └── unescaped: "  a\n"
-        │   └── closing_loc: (5,0)-(5,0) = "EOF\n"
-        ├── @ StringNode (location: (7,0)-(7,6))
+    @ StatementsNode (location: (1,0)-(88,6))
+    └── body: (length: 18)
+        ├── @ StringNode (location: (1,0)-(1,6))
         │   ├── flags: ∅
-        │   ├── opening_loc: (7,0)-(7,6) = "<<~EOF"
-        │   ├── content_loc: (8,0)-(8,0) = "  a\n"
-        │   ├── closing_loc: (9,0)-(9,0) = "EOF\n"
+        │   ├── opening_loc: (1,0)-(1,6) = "<<~EOF"
+        │   ├── content_loc: (2,0)-(2,0) = "  a\n"
+        │   ├── closing_loc: (3,0)-(3,0) = "EOF\n"
         │   └── unescaped: "a\n"
-        ├── @ InterpolatedStringNode (location: (11,0)-(11,6))
-        │   ├── opening_loc: (11,0)-(11,6) = "<<~EOF"
+        ├── @ InterpolatedStringNode (location: (5,0)-(5,6))
+        │   ├── opening_loc: (5,0)-(5,6) = "<<~EOF"
         │   ├── parts: (length: 3)
-        │   │   ├── @ StringNode (location: (12,0)-(12,0))
+        │   │   ├── @ StringNode (location: (6,0)-(6,0))
         │   │   │   ├── flags: ∅
         │   │   │   ├── opening_loc: ∅
-        │   │   │   ├── content_loc: (12,0)-(12,0) = "\ta\n"
+        │   │   │   ├── content_loc: (6,0)-(6,0) = "\ta\n"
         │   │   │   ├── closing_loc: ∅
         │   │   │   └── unescaped: "\ta\n"
-        │   │   ├── @ StringNode (location: (13,0)-(13,0))
+        │   │   ├── @ StringNode (location: (7,0)-(7,0))
         │   │   │   ├── flags: ∅
         │   │   │   ├── opening_loc: ∅
-        │   │   │   ├── content_loc: (13,0)-(13,0) = "  b\n"
+        │   │   │   ├── content_loc: (7,0)-(7,0) = "  b\n"
         │   │   │   ├── closing_loc: ∅
         │   │   │   └── unescaped: "b\n"
-        │   │   └── @ StringNode (location: (14,0)-(14,0))
+        │   │   └── @ StringNode (location: (8,0)-(8,0))
         │   │       ├── flags: ∅
         │   │       ├── opening_loc: ∅
-        │   │       ├── content_loc: (14,0)-(14,0) = "\t\tc\n"
+        │   │       ├── content_loc: (8,0)-(8,0) = "\t\tc\n"
         │   │       ├── closing_loc: ∅
         │   │       └── unescaped: "\t\tc\n"
-        │   └── closing_loc: (15,0)-(15,0) = "EOF\n"
-        ├── @ InterpolatedStringNode (location: (17,0)-(17,6))
-        │   ├── opening_loc: (17,0)-(17,6) = "<<~EOF"
+        │   └── closing_loc: (9,0)-(9,0) = "EOF\n"
+        ├── @ InterpolatedStringNode (location: (11,0)-(11,6))
+        │   ├── opening_loc: (11,0)-(11,6) = "<<~EOF"
         │   ├── parts: (length: 2)
-        │   │   ├── @ EmbeddedStatementsNode (location: (18,2)-(18,6))
-        │   │   │   ├── opening_loc: (18,2)-(18,4) = "\#{"
+        │   │   ├── @ EmbeddedStatementsNode (location: (12,2)-(12,6))
+        │   │   │   ├── opening_loc: (12,2)-(12,4) = "\#{"
         │   │   │   ├── statements:
-        │   │   │   │   @ StatementsNode (location: (18,4)-(18,5))
+        │   │   │   │   @ StatementsNode (location: (12,4)-(12,5))
         │   │   │   │   └── body: (length: 1)
-        │   │   │   │       └── @ IntegerNode (location: (18,4)-(18,5))
+        │   │   │   │       └── @ IntegerNode (location: (12,4)-(12,5))
         │   │   │   │           └── flags: decimal
-        │   │   │   └── closing_loc: (18,5)-(18,6) = "}"
-        │   │   └── @ StringNode (location: (18,6)-(18,0))
+        │   │   │   └── closing_loc: (12,5)-(12,6) = "}"
+        │   │   └── @ StringNode (location: (12,6)-(12,0))
         │   │       ├── flags: ∅
         │   │       ├── opening_loc: ∅
-        │   │       ├── content_loc: (18,6)-(18,0) = " a\n"
+        │   │       ├── content_loc: (12,6)-(12,0) = " a\n"
         │   │       ├── closing_loc: ∅
         │   │       └── unescaped: " a\n"
-        │   └── closing_loc: (19,0)-(19,0) = "EOF\n"
-        ├── @ InterpolatedStringNode (location: (21,0)-(21,6))
-        │   ├── opening_loc: (21,0)-(21,6) = "<<~EOF"
+        │   └── closing_loc: (13,0)-(13,0) = "EOF\n"
+        ├── @ InterpolatedStringNode (location: (15,0)-(15,6))
+        │   ├── opening_loc: (15,0)-(15,6) = "<<~EOF"
         │   ├── parts: (length: 3)
-        │   │   ├── @ StringNode (location: (22,0)-(22,4))
+        │   │   ├── @ StringNode (location: (16,0)-(16,4))
         │   │   │   ├── flags: ∅
         │   │   │   ├── opening_loc: ∅
-        │   │   │   ├── content_loc: (22,0)-(22,4) = "  a "
+        │   │   │   ├── content_loc: (16,0)-(16,4) = "  a "
         │   │   │   ├── closing_loc: ∅
         │   │   │   └── unescaped: "a "
-        │   │   ├── @ EmbeddedStatementsNode (location: (22,4)-(22,8))
-        │   │   │   ├── opening_loc: (22,4)-(22,6) = "\#{"
+        │   │   ├── @ EmbeddedStatementsNode (location: (16,4)-(16,8))
+        │   │   │   ├── opening_loc: (16,4)-(16,6) = "\#{"
         │   │   │   ├── statements:
-        │   │   │   │   @ StatementsNode (location: (22,6)-(22,7))
+        │   │   │   │   @ StatementsNode (location: (16,6)-(16,7))
         │   │   │   │   └── body: (length: 1)
-        │   │   │   │       └── @ IntegerNode (location: (22,6)-(22,7))
+        │   │   │   │       └── @ IntegerNode (location: (16,6)-(16,7))
         │   │   │   │           └── flags: decimal
-        │   │   │   └── closing_loc: (22,7)-(22,8) = "}"
-        │   │   └── @ StringNode (location: (22,8)-(22,0))
+        │   │   │   └── closing_loc: (16,7)-(16,8) = "}"
+        │   │   └── @ StringNode (location: (16,8)-(16,0))
         │   │       ├── flags: ∅
         │   │       ├── opening_loc: ∅
-        │   │       ├── content_loc: (22,8)-(22,0) = "\n"
+        │   │       ├── content_loc: (16,8)-(16,0) = "\n"
         │   │       ├── closing_loc: ∅
         │   │       └── unescaped: "\n"
-        │   └── closing_loc: (23,0)-(23,0) = "EOF\n"
-        ├── @ InterpolatedStringNode (location: (25,0)-(25,6))
-        │   ├── opening_loc: (25,0)-(25,6) = "<<~EOF"
+        │   └── closing_loc: (17,0)-(17,0) = "EOF\n"
+        ├── @ InterpolatedStringNode (location: (19,0)-(19,6))
+        │   ├── opening_loc: (19,0)-(19,6) = "<<~EOF"
         │   ├── parts: (length: 3)
-        │   │   ├── @ StringNode (location: (26,0)-(26,0))
+        │   │   ├── @ StringNode (location: (20,0)-(20,0))
         │   │   │   ├── flags: ∅
         │   │   │   ├── opening_loc: ∅
-        │   │   │   ├── content_loc: (26,0)-(26,0) = "  a\n"
+        │   │   │   ├── content_loc: (20,0)-(20,0) = "  a\n"
         │   │   │   ├── closing_loc: ∅
         │   │   │   └── unescaped: " a\n"
-        │   │   ├── @ EmbeddedStatementsNode (location: (27,1)-(27,5))
-        │   │   │   ├── opening_loc: (27,1)-(27,3) = "\#{"
+        │   │   ├── @ EmbeddedStatementsNode (location: (21,1)-(21,5))
+        │   │   │   ├── opening_loc: (21,1)-(21,3) = "\#{"
         │   │   │   ├── statements:
-        │   │   │   │   @ StatementsNode (location: (27,3)-(27,4))
+        │   │   │   │   @ StatementsNode (location: (21,3)-(21,4))
         │   │   │   │   └── body: (length: 1)
-        │   │   │   │       └── @ IntegerNode (location: (27,3)-(27,4))
+        │   │   │   │       └── @ IntegerNode (location: (21,3)-(21,4))
         │   │   │   │           └── flags: decimal
-        │   │   │   └── closing_loc: (27,4)-(27,5) = "}"
-        │   │   └── @ StringNode (location: (27,5)-(27,0))
+        │   │   │   └── closing_loc: (21,4)-(21,5) = "}"
+        │   │   └── @ StringNode (location: (21,5)-(21,0))
         │   │       ├── flags: ∅
         │   │       ├── opening_loc: ∅
-        │   │       ├── content_loc: (27,5)-(27,0) = "\n"
+        │   │       ├── content_loc: (21,5)-(21,0) = "\n"
         │   │       ├── closing_loc: ∅
         │   │       └── unescaped: "\n"
-        │   └── closing_loc: (28,0)-(28,0) = "EOF\n"
-        ├── @ InterpolatedStringNode (location: (30,0)-(30,6))
-        │   ├── opening_loc: (30,0)-(30,6) = "<<~EOF"
+        │   └── closing_loc: (22,0)-(22,0) = "EOF\n"
+        ├── @ InterpolatedStringNode (location: (24,0)-(24,6))
+        │   ├── opening_loc: (24,0)-(24,6) = "<<~EOF"
         │   ├── parts: (length: 3)
-        │   │   ├── @ StringNode (location: (31,0)-(31,0))
+        │   │   ├── @ StringNode (location: (25,0)-(25,0))
         │   │   │   ├── flags: ∅
         │   │   │   ├── opening_loc: ∅
-        │   │   │   ├── content_loc: (31,0)-(31,0) = "  a\n"
+        │   │   │   ├── content_loc: (25,0)-(25,0) = "  a\n"
         │   │   │   ├── closing_loc: ∅
         │   │   │   └── unescaped: "a\n"
-        │   │   ├── @ EmbeddedStatementsNode (location: (32,2)-(32,6))
-        │   │   │   ├── opening_loc: (32,2)-(32,4) = "\#{"
+        │   │   ├── @ EmbeddedStatementsNode (location: (26,2)-(26,6))
+        │   │   │   ├── opening_loc: (26,2)-(26,4) = "\#{"
         │   │   │   ├── statements:
-        │   │   │   │   @ StatementsNode (location: (32,4)-(32,5))
+        │   │   │   │   @ StatementsNode (location: (26,4)-(26,5))
         │   │   │   │   └── body: (length: 1)
-        │   │   │   │       └── @ IntegerNode (location: (32,4)-(32,5))
+        │   │   │   │       └── @ IntegerNode (location: (26,4)-(26,5))
         │   │   │   │           └── flags: decimal
-        │   │   │   └── closing_loc: (32,5)-(32,6) = "}"
-        │   │   └── @ StringNode (location: (32,6)-(32,0))
+        │   │   │   └── closing_loc: (26,5)-(26,6) = "}"
+        │   │   └── @ StringNode (location: (26,6)-(26,0))
         │   │       ├── flags: ∅
         │   │       ├── opening_loc: ∅
-        │   │       ├── content_loc: (32,6)-(32,0) = "\n"
+        │   │       ├── content_loc: (26,6)-(26,0) = "\n"
         │   │       ├── closing_loc: ∅
         │   │       └── unescaped: "\n"
-        │   └── closing_loc: (33,0)-(33,0) = "EOF\n"
-        ├── @ InterpolatedStringNode (location: (35,0)-(35,6))
-        │   ├── opening_loc: (35,0)-(35,6) = "<<~EOF"
+        │   └── closing_loc: (27,0)-(27,0) = "EOF\n"
+        ├── @ InterpolatedStringNode (location: (29,0)-(29,6))
+        │   ├── opening_loc: (29,0)-(29,6) = "<<~EOF"
         │   ├── parts: (length: 2)
-        │   │   ├── @ StringNode (location: (36,0)-(36,0))
+        │   │   ├── @ StringNode (location: (30,0)-(30,0))
         │   │   │   ├── flags: ∅
         │   │   │   ├── opening_loc: ∅
-        │   │   │   ├── content_loc: (36,0)-(36,0) = "  a\n"
+        │   │   │   ├── content_loc: (30,0)-(30,0) = "  a\n"
         │   │   │   ├── closing_loc: ∅
         │   │   │   └── unescaped: "a\n"
-        │   │   └── @ StringNode (location: (37,0)-(37,0))
+        │   │   └── @ StringNode (location: (31,0)-(31,0))
         │   │       ├── flags: ∅
         │   │       ├── opening_loc: ∅
-        │   │       ├── content_loc: (37,0)-(37,0) = "  b\n"
+        │   │       ├── content_loc: (31,0)-(31,0) = "  b\n"
         │   │       ├── closing_loc: ∅
         │   │       └── unescaped: "b\n"
-        │   └── closing_loc: (38,0)-(38,0) = "EOF\n"
-        ├── @ InterpolatedStringNode (location: (40,0)-(40,6))
-        │   ├── opening_loc: (40,0)-(40,6) = "<<~EOF"
+        │   └── closing_loc: (32,0)-(32,0) = "EOF\n"
+        ├── @ InterpolatedStringNode (location: (34,0)-(34,6))
+        │   ├── opening_loc: (34,0)-(34,6) = "<<~EOF"
         │   ├── parts: (length: 2)
-        │   │   ├── @ StringNode (location: (41,0)-(41,0))
+        │   │   ├── @ StringNode (location: (35,0)-(35,0))
         │   │   │   ├── flags: ∅
         │   │   │   ├── opening_loc: ∅
-        │   │   │   ├── content_loc: (41,0)-(41,0) = "  a\n"
+        │   │   │   ├── content_loc: (35,0)-(35,0) = "  a\n"
         │   │   │   ├── closing_loc: ∅
         │   │   │   └── unescaped: "a\n"
-        │   │   └── @ StringNode (location: (42,0)-(42,0))
+        │   │   └── @ StringNode (location: (36,0)-(36,0))
         │   │       ├── flags: ∅
         │   │       ├── opening_loc: ∅
-        │   │       ├── content_loc: (42,0)-(42,0) = "   b\n"
+        │   │       ├── content_loc: (36,0)-(36,0) = "   b\n"
         │   │       ├── closing_loc: ∅
         │   │       └── unescaped: " b\n"
-        │   └── closing_loc: (43,0)-(43,0) = "EOF\n"
-        ├── @ InterpolatedStringNode (location: (45,0)-(45,6))
-        │   ├── opening_loc: (45,0)-(45,6) = "<<~EOF"
+        │   └── closing_loc: (37,0)-(37,0) = "EOF\n"
+        ├── @ InterpolatedStringNode (location: (39,0)-(39,6))
+        │   ├── opening_loc: (39,0)-(39,6) = "<<~EOF"
         │   ├── parts: (length: 2)
-        │   │   ├── @ StringNode (location: (46,0)-(46,0))
+        │   │   ├── @ StringNode (location: (40,0)-(40,0))
         │   │   │   ├── flags: ∅
         │   │   │   ├── opening_loc: ∅
-        │   │   │   ├── content_loc: (46,0)-(46,0) = "\t\t\ta\n"
+        │   │   │   ├── content_loc: (40,0)-(40,0) = "\t\t\ta\n"
         │   │   │   ├── closing_loc: ∅
         │   │   │   └── unescaped: "\ta\n"
-        │   │   └── @ StringNode (location: (47,0)-(47,0))
+        │   │   └── @ StringNode (location: (41,0)-(41,0))
         │   │       ├── flags: ∅
         │   │       ├── opening_loc: ∅
-        │   │       ├── content_loc: (47,0)-(47,0) = "\t\tb\n"
+        │   │       ├── content_loc: (41,0)-(41,0) = "\t\tb\n"
         │   │       ├── closing_loc: ∅
         │   │       └── unescaped: "b\n"
-        │   └── closing_loc: (48,0)-(48,0) = "EOF\n"
-        ├── @ StringNode (location: (50,0)-(50,8))
+        │   └── closing_loc: (42,0)-(42,0) = "EOF\n"
+        ├── @ StringNode (location: (44,0)-(44,8))
         │   ├── flags: ∅
-        │   ├── opening_loc: (50,0)-(50,8) = "<<~'EOF'"
-        │   ├── content_loc: (51,0)-(51,0) = "  a \#{1}\n"
-        │   ├── closing_loc: (52,0)-(52,0) = "EOF\n"
+        │   ├── opening_loc: (44,0)-(44,8) = "<<~'EOF'"
+        │   ├── content_loc: (45,0)-(45,0) = "  a \#{1}\n"
+        │   ├── closing_loc: (46,0)-(46,0) = "EOF\n"
         │   └── unescaped: "a \#{1}\n"
-        ├── @ InterpolatedStringNode (location: (54,0)-(54,6))
-        │   ├── opening_loc: (54,0)-(54,6) = "<<~EOF"
+        ├── @ InterpolatedStringNode (location: (48,0)-(48,6))
+        │   ├── opening_loc: (48,0)-(48,6) = "<<~EOF"
         │   ├── parts: (length: 2)
-        │   │   ├── @ StringNode (location: (55,0)-(55,0))
+        │   │   ├── @ StringNode (location: (49,0)-(49,0))
         │   │   │   ├── flags: ∅
         │   │   │   ├── opening_loc: ∅
-        │   │   │   ├── content_loc: (55,0)-(55,0) = "\ta\n"
+        │   │   │   ├── content_loc: (49,0)-(49,0) = "\ta\n"
         │   │   │   ├── closing_loc: ∅
         │   │   │   └── unescaped: "a\n"
-        │   │   └── @ StringNode (location: (56,0)-(56,0))
+        │   │   └── @ StringNode (location: (50,0)-(50,0))
         │   │       ├── flags: ∅
         │   │       ├── opening_loc: ∅
-        │   │       ├── content_loc: (56,0)-(56,0) = "\t b\n"
+        │   │       ├── content_loc: (50,0)-(50,0) = "\t b\n"
         │   │       ├── closing_loc: ∅
         │   │       └── unescaped: " b\n"
-        │   └── closing_loc: (57,0)-(57,0) = "EOF\n"
-        ├── @ InterpolatedStringNode (location: (59,0)-(59,6))
-        │   ├── opening_loc: (59,0)-(59,6) = "<<~EOF"
+        │   └── closing_loc: (51,0)-(51,0) = "EOF\n"
+        ├── @ InterpolatedStringNode (location: (53,0)-(53,6))
+        │   ├── opening_loc: (53,0)-(53,6) = "<<~EOF"
         │   ├── parts: (length: 2)
-        │   │   ├── @ StringNode (location: (60,0)-(60,0))
+        │   │   ├── @ StringNode (location: (54,0)-(54,0))
         │   │   │   ├── flags: ∅
         │   │   │   ├── opening_loc: ∅
-        │   │   │   ├── content_loc: (60,0)-(60,0) = "\t a\n"
+        │   │   │   ├── content_loc: (54,0)-(54,0) = "\t a\n"
         │   │   │   ├── closing_loc: ∅
         │   │   │   └── unescaped: " a\n"
-        │   │   └── @ StringNode (location: (61,0)-(61,0))
+        │   │   └── @ StringNode (location: (55,0)-(55,0))
         │   │       ├── flags: ∅
         │   │       ├── opening_loc: ∅
-        │   │       ├── content_loc: (61,0)-(61,0) = "\tb\n"
+        │   │       ├── content_loc: (55,0)-(55,0) = "\tb\n"
         │   │       ├── closing_loc: ∅
         │   │       └── unescaped: "b\n"
-        │   └── closing_loc: (62,0)-(62,0) = "EOF\n"
-        ├── @ InterpolatedStringNode (location: (64,0)-(64,6))
-        │   ├── opening_loc: (64,0)-(64,6) = "<<~EOF"
+        │   └── closing_loc: (56,0)-(56,0) = "EOF\n"
+        ├── @ InterpolatedStringNode (location: (58,0)-(58,6))
+        │   ├── opening_loc: (58,0)-(58,6) = "<<~EOF"
         │   ├── parts: (length: 2)
-        │   │   ├── @ StringNode (location: (65,0)-(65,0))
+        │   │   ├── @ StringNode (location: (59,0)-(59,0))
         │   │   │   ├── flags: ∅
         │   │   │   ├── opening_loc: ∅
-        │   │   │   ├── content_loc: (65,0)-(65,0) = "  \ta\n"
+        │   │   │   ├── content_loc: (59,0)-(59,0) = "  \ta\n"
         │   │   │   ├── closing_loc: ∅
         │   │   │   └── unescaped: "a\n"
+        │   │   └── @ StringNode (location: (60,0)-(60,0))
+        │   │       ├── flags: ∅
+        │   │       ├── opening_loc: ∅
+        │   │       ├── content_loc: (60,0)-(60,0) = "        b\n"
+        │   │       ├── closing_loc: ∅
+        │   │       └── unescaped: "b\n"
+        │   └── closing_loc: (61,0)-(61,0) = "EOF\n"
+        ├── @ InterpolatedStringNode (location: (63,0)-(63,6))
+        │   ├── opening_loc: (63,0)-(63,6) = "<<~EOF"
+        │   ├── parts: (length: 3)
+        │   │   ├── @ StringNode (location: (64,0)-(64,0))
+        │   │   │   ├── flags: ∅
+        │   │   │   ├── opening_loc: ∅
+        │   │   │   ├── content_loc: (64,0)-(64,0) = "  a\n"
+        │   │   │   ├── closing_loc: ∅
+        │   │   │   └── unescaped: "a\n"
+        │   │   ├── @ StringNode (location: (65,0)-(65,0))
+        │   │   │   ├── flags: ∅
+        │   │   │   ├── opening_loc: ∅
+        │   │   │   ├── content_loc: (65,0)-(65,0) = "\n"
+        │   │   │   ├── closing_loc: ∅
+        │   │   │   └── unescaped: "\n"
         │   │   └── @ StringNode (location: (66,0)-(66,0))
         │   │       ├── flags: ∅
         │   │       ├── opening_loc: ∅
-        │   │       ├── content_loc: (66,0)-(66,0) = "        b\n"
+        │   │       ├── content_loc: (66,0)-(66,0) = "  b\n"
         │   │       ├── closing_loc: ∅
         │   │       └── unescaped: "b\n"
         │   └── closing_loc: (67,0)-(67,0) = "EOF\n"
@@ -277,7 +269,7 @@
         │   └── closing_loc: (73,0)-(73,0) = "EOF\n"
         ├── @ InterpolatedStringNode (location: (75,0)-(75,6))
         │   ├── opening_loc: (75,0)-(75,6) = "<<~EOF"
-        │   ├── parts: (length: 3)
+        │   ├── parts: (length: 5)
         │   │   ├── @ StringNode (location: (76,0)-(76,0))
         │   │   │   ├── flags: ∅
         │   │   │   ├── opening_loc: ∅
@@ -290,92 +282,70 @@
         │   │   │   ├── content_loc: (77,0)-(77,0) = "\n"
         │   │   │   ├── closing_loc: ∅
         │   │   │   └── unescaped: "\n"
-        │   │   └── @ StringNode (location: (78,0)-(78,0))
-        │   │       ├── flags: ∅
-        │   │       ├── opening_loc: ∅
-        │   │       ├── content_loc: (78,0)-(78,0) = "  b\n"
-        │   │       ├── closing_loc: ∅
-        │   │       └── unescaped: "b\n"
-        │   └── closing_loc: (79,0)-(79,0) = "EOF\n"
-        ├── @ InterpolatedStringNode (location: (81,0)-(81,6))
-        │   ├── opening_loc: (81,0)-(81,6) = "<<~EOF"
-        │   ├── parts: (length: 5)
-        │   │   ├── @ StringNode (location: (82,0)-(82,0))
-        │   │   │   ├── flags: ∅
-        │   │   │   ├── opening_loc: ∅
-        │   │   │   ├── content_loc: (82,0)-(82,0) = "  a\n"
-        │   │   │   ├── closing_loc: ∅
-        │   │   │   └── unescaped: "a\n"
-        │   │   ├── @ StringNode (location: (83,0)-(83,0))
-        │   │   │   ├── flags: ∅
-        │   │   │   ├── opening_loc: ∅
-        │   │   │   ├── content_loc: (83,0)-(83,0) = "\n"
-        │   │   │   ├── closing_loc: ∅
-        │   │   │   └── unescaped: "\n"
-        │   │   ├── @ StringNode (location: (84,0)-(84,0))
+        │   │   ├── @ StringNode (location: (78,0)-(78,0))
         │   │   │   ├── flags: ∅
         │   │   │   ├── opening_loc: ∅
-        │   │   │   ├── content_loc: (84,0)-(84,0) = "\n"
+        │   │   │   ├── content_loc: (78,0)-(78,0) = "\n"
         │   │   │   ├── closing_loc: ∅
         │   │   │   └── unescaped: "\n"
-        │   │   ├── @ StringNode (location: (85,0)-(85,0))
+        │   │   ├── @ StringNode (location: (79,0)-(79,0))
         │   │   │   ├── flags: ∅
         │   │   │   ├── opening_loc: ∅
-        │   │   │   ├── content_loc: (85,0)-(85,0) = "\n"
+        │   │   │   ├── content_loc: (79,0)-(79,0) = "\n"
         │   │   │   ├── closing_loc: ∅
         │   │   │   └── unescaped: "\n"
-        │   │   └── @ StringNode (location: (86,0)-(86,0))
+        │   │   └── @ StringNode (location: (80,0)-(80,0))
         │   │       ├── flags: ∅
         │   │       ├── opening_loc: ∅
-        │   │       ├── content_loc: (86,0)-(86,0) = "  b\n"
+        │   │       ├── content_loc: (80,0)-(80,0) = "  b\n"
         │   │       ├── closing_loc: ∅
         │   │       └── unescaped: "b\n"
-        │   └── closing_loc: (87,0)-(87,0) = "EOF\n"
-        ├── @ InterpolatedStringNode (location: (89,0)-(89,6))
-        │   ├── opening_loc: (89,0)-(89,6) = "<<~EOF"
+        │   └── closing_loc: (81,0)-(81,0) = "EOF\n"
+        ├── @ InterpolatedStringNode (location: (83,0)-(83,6))
+        │   ├── opening_loc: (83,0)-(83,6) = "<<~EOF"
         │   ├── parts: (length: 3)
-        │   │   ├── @ StringNode (location: (90,0)-(90,0))
+        │   │   ├── @ StringNode (location: (84,0)-(84,0))
         │   │   │   ├── flags: ∅
         │   │   │   ├── opening_loc: ∅
-        │   │   │   ├── content_loc: (90,0)-(90,0) = "\n"
+        │   │   │   ├── content_loc: (84,0)-(84,0) = "\n"
         │   │   │   ├── closing_loc: ∅
         │   │   │   └── unescaped: "\n"
-        │   │   ├── @ EmbeddedStatementsNode (location: (91,2)-(91,6))
-        │   │   │   ├── opening_loc: (91,2)-(91,4) = "\#{"
+        │   │   ├── @ EmbeddedStatementsNode (location: (85,2)-(85,6))
+        │   │   │   ├── opening_loc: (85,2)-(85,4) = "\#{"
         │   │   │   ├── statements:
-        │   │   │   │   @ StatementsNode (location: (91,4)-(91,5))
+        │   │   │   │   @ StatementsNode (location: (85,4)-(85,5))
         │   │   │   │   └── body: (length: 1)
-        │   │   │   │       └── @ IntegerNode (location: (91,4)-(91,5))
+        │   │   │   │       └── @ IntegerNode (location: (85,4)-(85,5))
         │   │   │   │           └── flags: decimal
-        │   │   │   └── closing_loc: (91,5)-(91,6) = "}"
-        │   │   └── @ StringNode (location: (91,6)-(91,0))
+        │   │   │   └── closing_loc: (85,5)-(85,6) = "}"
+        │   │   └── @ StringNode (location: (85,6)-(85,0))
         │   │       ├── flags: ∅
         │   │       ├── opening_loc: ∅
-        │   │       ├── content_loc: (91,6)-(91,0) = "a\n"
+        │   │       ├── content_loc: (85,6)-(85,0) = "a\n"
         │   │       ├── closing_loc: ∅
         │   │       └── unescaped: "a\n"
-        │   └── closing_loc: (92,0)-(92,0) = "    EOF\n"
-        └── @ InterpolatedStringNode (location: (94,0)-(94,6))
-            ├── opening_loc: (94,0)-(94,6) = "<<~EOT"
+        │   └── closing_loc: (86,0)-(86,0) = "    EOF\n"
+        └── @ InterpolatedStringNode (location: (88,0)-(88,6))
+            ├── opening_loc: (88,0)-(88,6) = "<<~EOT"
             ├── parts: (length: 3)
-            │   ├── @ EmbeddedStatementsNode (location: (95,2)-(95,6))
-            │   │   ├── opening_loc: (95,2)-(95,4) = "\#{"
+            │   ├── @ EmbeddedStatementsNode (location: (89,2)-(89,6))
+            │   │   ├── opening_loc: (89,2)-(89,4) = "\#{"
             │   │   ├── statements:
-            │   │   │   @ StatementsNode (location: (95,4)-(95,5))
+            │   │   │   @ StatementsNode (location: (89,4)-(89,5))
             │   │   │   └── body: (length: 1)
-            │   │   │       └── @ IntegerNode (location: (95,4)-(95,5))
+            │   │   │       └── @ IntegerNode (location: (89,4)-(89,5))
             │   │   │           └── flags: decimal
-            │   │   └── closing_loc: (95,5)-(95,6) = "}"
-            │   ├── @ StringNode (location: (95,6)-(95,0))
+            │   │   └── closing_loc: (89,5)-(89,6) = "}"
+            │   ├── @ StringNode (location: (89,6)-(89,0))
             │   │   ├── flags: ∅
             │   │   ├── opening_loc: ∅
-            │   │   ├── content_loc: (95,6)-(95,0) = "\n"
+            │   │   ├── content_loc: (89,6)-(89,0) = "\n"
             │   │   ├── closing_loc: ∅
             │   │   └── unescaped: "\n"
-            │   └── @ StringNode (location: (96,0)-(96,0))
+            │   └── @ StringNode (location: (90,0)-(90,0))
             │       ├── flags: ∅
             │       ├── opening_loc: ∅
-            │       ├── content_loc: (96,0)-(96,0) = "\tb\n"
+            │       ├── content_loc: (90,0)-(90,0) = "\tb\n"
             │       ├── closing_loc: ∅
             │       └── unescaped: "\tb\n"
-            └── closing_loc: (97,0)-(97,0) = "EOT\n"
+            └── closing_loc: (91,0)-(91,0) = "EOT\n"
diff --git a/test/prism/snapshots/whitequark/endless_method_forwarded_args_legacy.txt b/test/prism/snapshots/whitequark/endless_method_forwarded_args_legacy.txt
index 3117027f..c5b7ca8b 100644
--- a/test/prism/snapshots/whitequark/endless_method_forwarded_args_legacy.txt
+++ b/test/prism/snapshots/whitequark/endless_method_forwarded_args_legacy.txt
@@ -33,7 +33,7 @@
             │           ├── block: ∅
             │           ├── flags: ∅
             │           └── name: :bar
-            ├── locals: [:*, :&, :"..."]
+            ├── locals: [:"..."]
             ├── def_keyword_loc: (1,0)-(1,3) = "def"
             ├── operator_loc: ∅
             ├── lparen_loc: (1,7)-(1,8) = "("
diff --git a/test/prism/snapshots/whitequark/forward_arg.txt b/test/prism/snapshots/whitequark/forward_arg.txt
index 58e17007..6db649d9 100644
--- a/test/prism/snapshots/whitequark/forward_arg.txt
+++ b/test/prism/snapshots/whitequark/forward_arg.txt
@@ -33,7 +33,7 @@
             │           ├── block: ∅
             │           ├── flags: ∅
             │           └── name: :bar
-            ├── locals: [:*, :&, :"..."]
+            ├── locals: [:"..."]
             ├── def_keyword_loc: (1,0)-(1,3) = "def"
             ├── operator_loc: ∅
             ├── lparen_loc: (1,7)-(1,8) = "("
diff --git a/test/prism/snapshots/whitequark/forward_arg_with_open_args.txt b/test/prism/snapshots/whitequark/forward_arg_with_open_args.txt
index f2cf7c5e..28f8e2c8 100644
--- a/test/prism/snapshots/whitequark/forward_arg_with_open_args.txt
+++ b/test/prism/snapshots/whitequark/forward_arg_with_open_args.txt
@@ -37,7 +37,7 @@
         │   │           │           ├── block: ∅
         │   │           │           ├── flags: ∅
         │   │           │           └── name: :bar
-        │   │           ├── locals: [:*, :&, :"..."]
+        │   │           ├── locals: [:"..."]
         │   │           ├── def_keyword_loc: (1,1)-(1,4) = "def"
         │   │           ├── operator_loc: ∅
         │   │           ├── lparen_loc: ∅
@@ -80,7 +80,7 @@
         │   │           │           ├── block: ∅
         │   │           │           ├── flags: ∅
         │   │           │           └── name: :bar
-        │   │           ├── locals: [:*, :&, :"..."]
+        │   │           ├── locals: [:"..."]
         │   │           ├── def_keyword_loc: (5,1)-(5,4) = "def"
         │   │           ├── operator_loc: ∅
         │   │           ├── lparen_loc: ∅
@@ -104,7 +104,7 @@
         │   │   │   @ ForwardingParameterNode (location: (7,8)-(7,11))
         │   │   └── block: ∅
         │   ├── body: ∅
-        │   ├── locals: [:*, :&, :"..."]
+        │   ├── locals: [:"..."]
         │   ├── def_keyword_loc: (7,0)-(7,3) = "def"
         │   ├── operator_loc: ∅
         │   ├── lparen_loc: ∅
@@ -141,7 +141,7 @@
         │   │           ├── block: ∅
         │   │           ├── flags: ∅
         │   │           └── name: :bar
-        │   ├── locals: [:*, :&, :"..."]
+        │   ├── locals: [:"..."]
         │   ├── def_keyword_loc: (10,0)-(10,3) = "def"
         │   ├── operator_loc: ∅
         │   ├── lparen_loc: ∅
@@ -180,7 +180,7 @@
         │   │           ├── block: ∅
         │   │           ├── flags: ∅
         │   │           └── name: :bar
-        │   ├── locals: [:a, :*, :&, :"..."]
+        │   ├── locals: [:a, :"..."]
         │   ├── def_keyword_loc: (12,0)-(12,3) = "def"
         │   ├── operator_loc: ∅
         │   ├── lparen_loc: ∅
@@ -219,7 +219,7 @@
         │   │           ├── block: ∅
         │   │           ├── flags: ∅
         │   │           └── name: :bar
-        │   ├── locals: [:a, :*, :&, :"..."]
+        │   ├── locals: [:a, :"..."]
         │   ├── def_keyword_loc: (16,0)-(16,3) = "def"
         │   ├── operator_loc: ∅
         │   ├── lparen_loc: ∅
@@ -250,7 +250,7 @@
         │   │   │   @ ForwardingParameterNode (location: (18,18)-(18,21))
         │   │   └── block: ∅
         │   ├── body: ∅
-        │   ├── locals: [:a, :b, :*, :&, :"..."]
+        │   ├── locals: [:a, :b, :"..."]
         │   ├── def_keyword_loc: (18,0)-(18,3) = "def"
         │   ├── operator_loc: ∅
         │   ├── lparen_loc: ∅
@@ -294,7 +294,7 @@
         │   │           ├── block: ∅
         │   │           ├── flags: ∅
         │   │           └── name: :bar
-        │   ├── locals: [:b, :*, :&, :"..."]
+        │   ├── locals: [:b, :"..."]
         │   ├── def_keyword_loc: (21,0)-(21,3) = "def"
         │   ├── operator_loc: ∅
         │   ├── lparen_loc: ∅
@@ -338,7 +338,7 @@
         │   │           ├── block: ∅
         │   │           ├── flags: ∅
         │   │           └── name: :bar
-        │   ├── locals: [:b, :*, :&, :"..."]
+        │   ├── locals: [:b, :"..."]
         │   ├── def_keyword_loc: (25,0)-(25,3) = "def"
         │   ├── operator_loc: ∅
         │   ├── lparen_loc: ∅
@@ -377,7 +377,7 @@
             │           ├── block: ∅
             │           ├── flags: ∅
             │           └── name: :bar
-            ├── locals: [:a, :*, :&, :"..."]
+            ├── locals: [:a, :"..."]
             ├── def_keyword_loc: (27,0)-(27,3) = "def"
             ├── operator_loc: ∅
             ├── lparen_loc: (27,7)-(27,8) = "("
diff --git a/test/prism/snapshots/whitequark/forward_args_legacy.txt b/test/prism/snapshots/whitequark/forward_args_legacy.txt
index 8ab9fd40..281e5e97 100644
--- a/test/prism/snapshots/whitequark/forward_args_legacy.txt
+++ b/test/prism/snapshots/whitequark/forward_args_legacy.txt
@@ -33,7 +33,7 @@
         │   │           ├── block: ∅
         │   │           ├── flags: ∅
         │   │           └── name: :bar
-        │   ├── locals: [:*, :&, :"..."]
+        │   ├── locals: [:"..."]
         │   ├── def_keyword_loc: (1,0)-(1,3) = "def"
         │   ├── operator_loc: ∅
         │   ├── lparen_loc: (1,7)-(1,8) = "("
@@ -55,7 +55,7 @@
         │   │   │   @ ForwardingParameterNode (location: (3,8)-(3,11))
         │   │   └── block: ∅
         │   ├── body: ∅
-        │   ├── locals: [:*, :&, :"..."]
+        │   ├── locals: [:"..."]
         │   ├── def_keyword_loc: (3,0)-(3,3) = "def"
         │   ├── operator_loc: ∅
         │   ├── lparen_loc: (3,7)-(3,8) = "("
@@ -88,7 +88,7 @@
             │           │       └── @ ForwardingArgumentsNode (location: (5,20)-(5,23))
             │           ├── rparen_loc: (5,23)-(5,24) = ")"
             │           └── block: ∅
-            ├── locals: [:*, :&, :"..."]
+            ├── locals: [:"..."]
             ├── def_keyword_loc: (5,0)-(5,3) = "def"
             ├── operator_loc: ∅
             ├── lparen_loc: (5,7)-(5,8) = "("
diff --git a/test/prism/snapshots/whitequark/trailing_forward_arg.txt b/test/prism/snapshots/whitequark/trailing_forward_arg.txt
index f30c0b1e..15c8b4ac 100644
--- a/test/prism/snapshots/whitequark/trailing_forward_arg.txt
+++ b/test/prism/snapshots/whitequark/trailing_forward_arg.txt
@@ -42,7 +42,7 @@
             │           ├── block: ∅
             │           ├── flags: ∅
             │           └── name: :bar
-            ├── locals: [:a, :b, :*, :&, :"..."]
+            ├── locals: [:a, :b, :"..."]
             ├── def_keyword_loc: (1,0)-(1,3) = "def"
             ├── operator_loc: ∅
             ├── lparen_loc: (1,7)-(1,8) = "("