Repository: ruby/prism
Pull request #2098 (2023-12-15 18:55:37)

String literal hash keys should be frozen
String literal hash keys can't be mutated by the user so we should mark them as frozen. We were seeing instructions for hashes with string literal keys using two `putstring` instructions when it should be a `putobject` and `putstring`.

Code example:

```ruby
{ "a" => "b" }
```

Instructions before:

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(2,14)>
0000 putobject                              "a"                       (   2)[Li]
0002 putstring                              "b"
0004 newhash                                2
0006 leave
"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(1,14)>
0000 putstring                              "a"                       (   1)[Li]
0002 putstring                              "b"
0004 newhash                                2
0006 leave
```

Instructions after:

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(2,14)>
0000 putobject                              "a"                       (   2)[Li]
0002 putstring                              "b"
0004 newhash                                2
0006 leave

"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(1,14)>
0000 putobject                              "a"                       (   1)[Li]
0002 putstring                              "b"
0004 newhash                                2
0006 leave
```


Patch:
diff --git a/.github/workflows/rust-bindings.yml b/.github/workflows/rust-bindings.yml
index 0887496c..e18d830f 100644
--- a/.github/workflows/rust-bindings.yml
+++ b/.github/workflows/rust-bindings.yml
@@ -105,36 +105,32 @@ jobs:
       - name: Test with sanitizer
         run: bundle exec rake cargo:sanitize:${{ matrix.sanitizer }}
 
-  # We need to figure out what to do here. When you run publish it checks
-  # against the latest version published to crates, which means if we have any
-  # breaking changes in the bindings then this fails.
-  #
-  # publish:
-  #   name: cargo:publish
-  #   strategy:
-  #     fail-fast: false
-  #   runs-on: ubuntu-latest
-  #   steps:
-  #     - uses: actions/checkout@v3
-  #     - name: Set up Ruby
-  #       uses: ruby/setup-ruby@v1
-  #       with:
-  #         ruby-version: head
-  #         bundler-cache: true
-  #     - name: Set up Rust
-  #       uses: dtolnay/rust-toolchain@master
-  #       with:
-  #         toolchain: "1.71.1"
-  #         targets: wasm32-wasi
-  #     - uses: actions/cache@v3
-  #       with:
-  #         path: |
-  #           ~/.cargo/registry
-  #           ~/.cargo/git
-  #           target
-  #         key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
-  #         restore-keys: |
-  #           ${{ runner.os }}-cargo-${{ hashFiles('Cargo.toml') }}
-  #           ${{ runner.os }}-cargo
-  #     - name: Publish crates (dry-run)
-  #       run: bundle exec rake cargo:publish:dry
+  publish:
+    name: cargo:publish
+    strategy:
+      fail-fast: false
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v3
+      - name: Set up Ruby
+        uses: ruby/setup-ruby@v1
+        with:
+          ruby-version: head
+          bundler-cache: true
+      - name: Set up Rust
+        uses: dtolnay/rust-toolchain@master
+        with:
+          toolchain: "1.71.1"
+          targets: wasm32-wasi
+      - uses: actions/cache@v3
+        with:
+          path: |
+            ~/.cargo/registry
+            ~/.cargo/git
+            target
+          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
+          restore-keys: |
+            ${{ runner.os }}-cargo-${{ hashFiles('Cargo.toml') }}
+            ${{ runner.os }}-cargo
+      - name: Publish crates (dry-run)
+        run: bundle exec rake cargo:publish:dry
diff --git a/config.yml b/config.yml
index 7bbe88e6..d3b6b087 100644
--- a/config.yml
+++ b/config.yml
@@ -368,8 +368,8 @@ flags:
     comment: Flags for integer nodes that correspond to the base of the integer.
   - name: KeywordHashNodeFlags
     values:
-      - name: SYMBOL_KEYS
-        comment: "a keyword hash which only has `AssocNode` elements all with symbol keys, which means the elements can be treated as keyword arguments"
+      - name: STATIC_KEYS
+        comment: "a keyword hash which only has `AssocNode` elements all with static literal keys, which means the elements can be treated as keyword arguments"
     comment: Flags for keyword hash nodes.
   - name: LoopFlags
     values:
diff --git a/include/prism/parser.h b/include/prism/parser.h
index 2c58131b..7f26054f 100644
--- a/include/prism/parser.h
+++ b/include/prism/parser.h
@@ -17,6 +17,12 @@
 
 #include <stdbool.h>
 
+// TODO: remove this by renaming the original flag
+/**
+ * Temporary alias for the PM_NODE_FLAG_STATIC_KEYS flag.
+ */
+#define PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS PM_KEYWORD_HASH_NODE_FLAGS_STATIC_KEYS
+
 /**
  * This enum provides various bits that represent different kinds of states that
  * the lexer can track. This is used to determine which kind of token to return
diff --git a/src/prism.c b/src/prism.c
index a382a6b1..ec319f2c 100644
--- a/src/prism.c
+++ b/src/prism.c
@@ -1340,6 +1340,11 @@ pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *oper
         flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL;
     }
 
+    // Hash string keys should be frozen
+    if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
+        key->flags |= PM_STRING_FLAGS_FROZEN;
+    }
+
     *node = (pm_assoc_node_t) {
         {
             .type = PM_ASSOC_NODE,


Test patch:
diff --git a/test/prism/snapshots/arrays.txt b/test/prism/snapshots/arrays.txt
index 93f5c8fb..d31cd7af 100644
--- a/test/prism/snapshots/arrays.txt
+++ b/test/prism/snapshots/arrays.txt
@@ -79,7 +79,7 @@
         │   ├── flags: ∅
         │   ├── elements: (length: 1)
         │   │   └── @ KeywordHashNode (location: (5,1)-(5,12))
-        │   │       ├── flags: symbol_keys
+        │   │       ├── flags: static_keys
         │   │       └── elements: (length: 1)
         │   │           └── @ AssocNode (location: (5,1)-(5,12))
         │   │               ├── key:
diff --git a/test/prism/snapshots/if.txt b/test/prism/snapshots/if.txt
index a5ffeac2..6733e57b 100644
--- a/test/prism/snapshots/if.txt
+++ b/test/prism/snapshots/if.txt
@@ -250,7 +250,7 @@
         │   │           │   ├── flags: ∅
         │   │           │   └── arguments: (length: 1)
         │   │           │       └── @ KeywordHashNode (location: (25,4)-(25,6))
-        │   │           │           ├── flags: symbol_keys
+        │   │           │           ├── flags: static_keys
         │   │           │           └── elements: (length: 1)
         │   │           │               └── @ AssocNode (location: (25,4)-(25,6))
         │   │           │                   ├── key:
diff --git a/test/prism/snapshots/method_calls.txt b/test/prism/snapshots/method_calls.txt
index f8de181d..65f0d1df 100644
--- a/test/prism/snapshots/method_calls.txt
+++ b/test/prism/snapshots/method_calls.txt
@@ -782,7 +782,7 @@
         │   │       │   ├── closing_loc: ∅
         │   │       │   └── unescaped: "a"
         │   │       └── @ KeywordHashNode (location: (60,8)-(60,32))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 2)
         │   │               ├── @ AssocNode (location: (60,8)-(60,22))
         │   │               │   ├── key:
@@ -914,7 +914,7 @@
         │   │       │   ├── closing_loc: ∅
         │   │       │   └── unescaped: "a"
         │   │       └── @ KeywordHashNode (location: (64,8)-(64,15))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (64,8)-(64,15))
         │   │                   ├── key:
@@ -983,7 +983,7 @@
         │   │   ├── flags: ∅
         │   │   └── arguments: (length: 1)
         │   │       └── @ KeywordHashNode (location: (66,3)-(66,17))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (66,3)-(66,17))
         │   │                   ├── key:
@@ -1173,7 +1173,7 @@
         │   │   ├── flags: ∅
         │   │   └── arguments: (length: 1)
         │   │       └── @ KeywordHashNode (location: (74,3)-(74,20))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (74,3)-(74,20))
         │   │                   ├── key:
@@ -1236,7 +1236,7 @@
         │   │       │   ├── closing_loc: ∅
         │   │       │   └── unescaped: "a"
         │   │       └── @ KeywordHashNode (location: (82,0)-(82,5))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (82,0)-(82,5))
         │   │                   ├── key:
@@ -1287,7 +1287,7 @@
         │   │   ├── flags: ∅
         │   │   └── arguments: (length: 1)
         │   │       └── @ KeywordHashNode (location: (87,4)-(87,21))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 2)
         │   │               ├── @ AssocNode (location: (87,4)-(87,11))
         │   │               │   ├── key:
@@ -1336,7 +1336,7 @@
         │   │       ├── @ IntegerNode (location: (89,10)-(89,11))
         │   │       │   └── flags: decimal
         │   │       └── @ KeywordHashNode (location: (89,13)-(89,21))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (89,13)-(89,21))
         │   │                   ├── key:
@@ -1527,7 +1527,7 @@
         │   │   ├── flags: ∅
         │   │   └── arguments: (length: 1)
         │   │       └── @ KeywordHashNode (location: (103,4)-(103,11))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (103,4)-(103,11))
         │   │                   ├── key:
@@ -1555,7 +1555,7 @@
         │   │   ├── flags: ∅
         │   │   └── arguments: (length: 1)
         │   │       └── @ KeywordHashNode (location: (105,4)-(105,28))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (105,4)-(105,28))
         │   │                   ├── key:
@@ -1612,7 +1612,7 @@
         │   │   ├── flags: ∅
         │   │   └── arguments: (length: 1)
         │   │       └── @ KeywordHashNode (location: (107,4)-(107,24))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (107,4)-(107,24))
         │   │                   ├── key:
diff --git a/test/prism/snapshots/rescue.txt b/test/prism/snapshots/rescue.txt
index 12607e8b..3f9dc426 100644
--- a/test/prism/snapshots/rescue.txt
+++ b/test/prism/snapshots/rescue.txt
@@ -343,7 +343,7 @@
             │   │           │   ├── flags: ∅
             │   │           │   └── arguments: (length: 1)
             │   │           │       └── @ KeywordHashNode (location: (29,4)-(29,6))
-            │   │           │           ├── flags: symbol_keys
+            │   │           │           ├── flags: static_keys
             │   │           │           └── elements: (length: 1)
             │   │           │               └── @ AssocNode (location: (29,4)-(29,6))
             │   │           │                   ├── key:
diff --git a/test/prism/snapshots/seattlerb/assoc_label.txt b/test/prism/snapshots/seattlerb/assoc_label.txt
index c8526358..1d65eef3 100644
--- a/test/prism/snapshots/seattlerb/assoc_label.txt
+++ b/test/prism/snapshots/seattlerb/assoc_label.txt
@@ -15,7 +15,7 @@
             │   ├── flags: ∅
             │   └── arguments: (length: 1)
             │       └── @ KeywordHashNode (location: (1,2)-(1,5))
-            │           ├── flags: symbol_keys
+            │           ├── flags: static_keys
             │           └── elements: (length: 1)
             │               └── @ AssocNode (location: (1,2)-(1,5))
             │                   ├── key:
diff --git a/test/prism/snapshots/seattlerb/bug_249.txt b/test/prism/snapshots/seattlerb/bug_249.txt
index c2934914..4c684f32 100644
--- a/test/prism/snapshots/seattlerb/bug_249.txt
+++ b/test/prism/snapshots/seattlerb/bug_249.txt
@@ -66,7 +66,7 @@
             │       │   ├── closing_loc: ∅
             │       │   └── block: ∅
             │       └── @ KeywordHashNode (location: (4,11)-(4,28))
-            │           ├── flags: symbol_keys
+            │           ├── flags: static_keys
             │           └── elements: (length: 1)
             │               └── @ AssocNode (location: (4,11)-(4,28))
             │                   ├── key:
diff --git a/test/prism/snapshots/seattlerb/bug_hash_args.txt b/test/prism/snapshots/seattlerb/bug_hash_args.txt
index 7900bbe0..cea1fc8d 100644
--- a/test/prism/snapshots/seattlerb/bug_hash_args.txt
+++ b/test/prism/snapshots/seattlerb/bug_hash_args.txt
@@ -21,7 +21,7 @@
             │       │   ├── closing_loc: ∅
             │       │   └── unescaped: "bar"
             │       └── @ KeywordHashNode (location: (1,10)-(1,18))
-            │           ├── flags: symbol_keys
+            │           ├── flags: static_keys
             │           └── elements: (length: 1)
             │               └── @ AssocNode (location: (1,10)-(1,18))
             │                   ├── key:
diff --git a/test/prism/snapshots/seattlerb/bug_hash_args_trailing_comma.txt b/test/prism/snapshots/seattlerb/bug_hash_args_trailing_comma.txt
index 2b2b2462..e4c2a10f 100644
--- a/test/prism/snapshots/seattlerb/bug_hash_args_trailing_comma.txt
+++ b/test/prism/snapshots/seattlerb/bug_hash_args_trailing_comma.txt
@@ -21,7 +21,7 @@
             │       │   ├── closing_loc: ∅
             │       │   └── unescaped: "bar"
             │       └── @ KeywordHashNode (location: (1,10)-(1,18))
-            │           ├── flags: symbol_keys
+            │           ├── flags: static_keys
             │           └── elements: (length: 1)
             │               └── @ AssocNode (location: (1,10)-(1,18))
             │                   ├── key:
diff --git a/test/prism/snapshots/seattlerb/call_args_assoc_quoted.txt b/test/prism/snapshots/seattlerb/call_args_assoc_quoted.txt
index 9426531d..958231a2 100644
--- a/test/prism/snapshots/seattlerb/call_args_assoc_quoted.txt
+++ b/test/prism/snapshots/seattlerb/call_args_assoc_quoted.txt
@@ -57,7 +57,7 @@
         │   │   ├── flags: ∅
         │   │   └── arguments: (length: 1)
         │   │       └── @ KeywordHashNode (location: (3,2)-(3,8))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (3,2)-(3,8))
         │   │                   ├── key:
@@ -85,7 +85,7 @@
             │   ├── flags: ∅
             │   └── arguments: (length: 1)
             │       └── @ KeywordHashNode (location: (5,2)-(5,8))
-            │           ├── flags: symbol_keys
+            │           ├── flags: static_keys
             │           └── elements: (length: 1)
             │               └── @ AssocNode (location: (5,2)-(5,8))
             │                   ├── key:
diff --git a/test/prism/snapshots/seattlerb/call_array_lit_inline_hash.txt b/test/prism/snapshots/seattlerb/call_array_lit_inline_hash.txt
index f572729b..f8cde2f6 100644
--- a/test/prism/snapshots/seattlerb/call_array_lit_inline_hash.txt
+++ b/test/prism/snapshots/seattlerb/call_array_lit_inline_hash.txt
@@ -24,7 +24,7 @@
             │           │   │   ├── closing_loc: ∅
             │           │   │   └── unescaped: "b"
             │           │   └── @ KeywordHashNode (location: (1,7)-(1,14))
-            │           │       ├── flags: symbol_keys
+            │           │       ├── flags: static_keys
             │           │       └── elements: (length: 1)
             │           │           └── @ AssocNode (location: (1,7)-(1,14))
             │           │               ├── key:
diff --git a/test/prism/snapshots/seattlerb/call_assoc_new.txt b/test/prism/snapshots/seattlerb/call_assoc_new.txt
index decf68ae..6d121252 100644
--- a/test/prism/snapshots/seattlerb/call_assoc_new.txt
+++ b/test/prism/snapshots/seattlerb/call_assoc_new.txt
@@ -15,7 +15,7 @@
             │   ├── flags: ∅
             │   └── arguments: (length: 1)
             │       └── @ KeywordHashNode (location: (1,2)-(1,5))
-            │           ├── flags: symbol_keys
+            │           ├── flags: static_keys
             │           └── elements: (length: 1)
             │               └── @ AssocNode (location: (1,2)-(1,5))
             │                   ├── key:
diff --git a/test/prism/snapshots/seattlerb/call_assoc_new_if_multiline.txt b/test/prism/snapshots/seattlerb/call_assoc_new_if_multiline.txt
index c9e0ff96..1c079f9d 100644
--- a/test/prism/snapshots/seattlerb/call_assoc_new_if_multiline.txt
+++ b/test/prism/snapshots/seattlerb/call_assoc_new_if_multiline.txt
@@ -15,7 +15,7 @@
             │   ├── flags: ∅
             │   └── arguments: (length: 1)
             │       └── @ KeywordHashNode (location: (1,2)-(5,3))
-            │           ├── flags: symbol_keys
+            │           ├── flags: static_keys
             │           └── elements: (length: 1)
             │               └── @ AssocNode (location: (1,2)-(5,3))
             │                   ├── key:
diff --git a/test/prism/snapshots/seattlerb/difficult2_.txt b/test/prism/snapshots/seattlerb/difficult2_.txt
index 72cac371..a81b0ce4 100644
--- a/test/prism/snapshots/seattlerb/difficult2_.txt
+++ b/test/prism/snapshots/seattlerb/difficult2_.txt
@@ -53,7 +53,7 @@
             │   ├── flags: ∅
             │   └── arguments: (length: 1)
             │       └── @ KeywordHashNode (location: (2,2)-(2,6))
-            │           ├── flags: symbol_keys
+            │           ├── flags: static_keys
             │           └── elements: (length: 1)
             │               └── @ AssocNode (location: (2,2)-(2,6))
             │                   ├── key:
diff --git a/test/prism/snapshots/seattlerb/multiline_hash_declaration.txt b/test/prism/snapshots/seattlerb/multiline_hash_declaration.txt
index f377bda1..efa6fa24 100644
--- a/test/prism/snapshots/seattlerb/multiline_hash_declaration.txt
+++ b/test/prism/snapshots/seattlerb/multiline_hash_declaration.txt
@@ -15,7 +15,7 @@
         │   │   ├── flags: ∅
         │   │   └── arguments: (length: 1)
         │   │       └── @ KeywordHashNode (location: (1,2)-(3,1))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (1,2)-(3,1))
         │   │                   ├── key:
@@ -45,7 +45,7 @@
         │   │   ├── flags: ∅
         │   │   └── arguments: (length: 1)
         │   │       └── @ KeywordHashNode (location: (5,2)-(6,1))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (5,2)-(6,1))
         │   │                   ├── key:
@@ -75,7 +75,7 @@
             │   ├── flags: ∅
             │   └── arguments: (length: 1)
             │       └── @ KeywordHashNode (location: (8,2)-(8,11))
-            │           ├── flags: symbol_keys
+            │           ├── flags: static_keys
             │           └── elements: (length: 1)
             │               └── @ AssocNode (location: (8,2)-(8,11))
             │                   ├── key:
diff --git a/test/prism/snapshots/seattlerb/quoted_symbol_hash_arg.txt b/test/prism/snapshots/seattlerb/quoted_symbol_hash_arg.txt
index 8730eb19..59bd8f02 100644
--- a/test/prism/snapshots/seattlerb/quoted_symbol_hash_arg.txt
+++ b/test/prism/snapshots/seattlerb/quoted_symbol_hash_arg.txt
@@ -15,7 +15,7 @@
             │   ├── flags: ∅
             │   └── arguments: (length: 1)
             │       └── @ KeywordHashNode (location: (1,5)-(1,12))
-            │           ├── flags: symbol_keys
+            │           ├── flags: static_keys
             │           └── elements: (length: 1)
             │               └── @ AssocNode (location: (1,5)-(1,12))
             │                   ├── key:
diff --git a/test/prism/snapshots/seattlerb/return_call_assocs.txt b/test/prism/snapshots/seattlerb/return_call_assocs.txt
index 98b7943b..8baf6c4c 100644
--- a/test/prism/snapshots/seattlerb/return_call_assocs.txt
+++ b/test/prism/snapshots/seattlerb/return_call_assocs.txt
@@ -12,7 +12,7 @@
         │           ├── @ IntegerNode (location: (1,7)-(1,8))
         │           │   └── flags: decimal
         │           └── @ KeywordHashNode (location: (1,10)-(1,17))
-        │               ├── flags: symbol_keys
+        │               ├── flags: static_keys
         │               └── elements: (length: 1)
         │                   └── @ AssocNode (location: (1,10)-(1,17))
         │                       ├── key:
@@ -35,7 +35,7 @@
         │           ├── @ IntegerNode (location: (3,7)-(3,8))
         │           │   └── flags: decimal
         │           └── @ KeywordHashNode (location: (3,10)-(3,26))
-        │               ├── flags: symbol_keys
+        │               ├── flags: static_keys
         │               └── elements: (length: 2)
         │                   ├── @ AssocNode (location: (3,10)-(3,17))
         │                   │   ├── key:
@@ -79,7 +79,7 @@
         │               │   ├── flags: ∅
         │               │   └── arguments: (length: 1)
         │               │       └── @ KeywordHashNode (location: (5,9)-(5,14))
-        │               │           ├── flags: symbol_keys
+        │               │           ├── flags: static_keys
         │               │           └── elements: (length: 1)
         │               │               └── @ AssocNode (location: (5,9)-(5,14))
         │               │                   ├── key:
@@ -113,7 +113,7 @@
         │               │   ├── flags: ∅
         │               │   └── arguments: (length: 1)
         │               │       └── @ KeywordHashNode (location: (7,9)-(7,12))
-        │               │           ├── flags: symbol_keys
+        │               │           ├── flags: static_keys
         │               │           └── elements: (length: 1)
         │               │               └── @ AssocNode (location: (7,9)-(7,12))
         │               │                   ├── key:
@@ -147,7 +147,7 @@
         │               │   ├── flags: ∅
         │               │   └── arguments: (length: 1)
         │               │       └── @ KeywordHashNode (location: (9,9)-(9,12))
-        │               │           ├── flags: symbol_keys
+        │               │           ├── flags: static_keys
         │               │           └── elements: (length: 1)
         │               │               └── @ AssocNode (location: (9,9)-(9,12))
         │               │                   ├── key:
diff --git a/test/prism/snapshots/seattlerb/yield_call_assocs.txt b/test/prism/snapshots/seattlerb/yield_call_assocs.txt
index 95d64eaa..82d1765f 100644
--- a/test/prism/snapshots/seattlerb/yield_call_assocs.txt
+++ b/test/prism/snapshots/seattlerb/yield_call_assocs.txt
@@ -13,7 +13,7 @@
         │   │       ├── @ IntegerNode (location: (1,6)-(1,7))
         │   │       │   └── flags: decimal
         │   │       └── @ KeywordHashNode (location: (1,9)-(1,16))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (1,9)-(1,16))
         │   │                   ├── key:
@@ -38,7 +38,7 @@
         │   │       ├── @ IntegerNode (location: (3,6)-(3,7))
         │   │       │   └── flags: decimal
         │   │       └── @ KeywordHashNode (location: (3,9)-(3,25))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 2)
         │   │               ├── @ AssocNode (location: (3,9)-(3,16))
         │   │               │   ├── key:
@@ -84,7 +84,7 @@
         │   │           │   ├── flags: ∅
         │   │           │   └── arguments: (length: 1)
         │   │           │       └── @ KeywordHashNode (location: (5,8)-(5,13))
-        │   │           │           ├── flags: symbol_keys
+        │   │           │           ├── flags: static_keys
         │   │           │           └── elements: (length: 1)
         │   │           │               └── @ AssocNode (location: (5,8)-(5,13))
         │   │           │                   ├── key:
@@ -120,7 +120,7 @@
         │   │           │   ├── flags: ∅
         │   │           │   └── arguments: (length: 1)
         │   │           │       └── @ KeywordHashNode (location: (7,8)-(7,11))
-        │   │           │           ├── flags: symbol_keys
+        │   │           │           ├── flags: static_keys
         │   │           │           └── elements: (length: 1)
         │   │           │               └── @ AssocNode (location: (7,8)-(7,11))
         │   │           │                   ├── key:
@@ -156,7 +156,7 @@
         │   │           │   ├── flags: ∅
         │   │           │   └── arguments: (length: 1)
         │   │           │       └── @ KeywordHashNode (location: (9,8)-(9,11))
-        │   │           │           ├── flags: symbol_keys
+        │   │           │           ├── flags: static_keys
         │   │           │           └── elements: (length: 1)
         │   │           │               └── @ AssocNode (location: (9,8)-(9,11))
         │   │           │                   ├── key:
diff --git a/test/prism/snapshots/unparser/corpus/literal/literal.txt b/test/prism/snapshots/unparser/corpus/literal/literal.txt
index 21ae9f67..a26b9251 100644
--- a/test/prism/snapshots/unparser/corpus/literal/literal.txt
+++ b/test/prism/snapshots/unparser/corpus/literal/literal.txt
@@ -9,7 +9,7 @@
         │   │   ├── @ AssocNode (location: (1,2)-(1,21))
         │   │   │   ├── key:
         │   │   │   │   @ StringNode (location: (1,2)-(1,7))
-        │   │   │   │   ├── flags: ∅
+        │   │   │   │   ├── flags: frozen
         │   │   │   │   ├── opening_loc: (1,2)-(1,3) = "\""
         │   │   │   │   ├── content_loc: (1,3)-(1,6) = "foo"
         │   │   │   │   ├── closing_loc: (1,6)-(1,7) = "\""
@@ -39,7 +39,7 @@
         │   │   └── @ AssocNode (location: (1,23)-(1,36))
         │   │       ├── key:
         │   │       │   @ StringNode (location: (1,23)-(1,28))
-        │   │       │   ├── flags: ∅
+        │   │       │   ├── flags: frozen
         │   │       │   ├── opening_loc: (1,23)-(1,24) = "\""
         │   │       │   ├── content_loc: (1,24)-(1,27) = "bar"
         │   │       │   ├── closing_loc: (1,27)-(1,28) = "\""
@@ -59,7 +59,7 @@
         │   │   ├── @ AssocNode (location: (4,2)-(4,14))
         │   │   │   ├── key:
         │   │   │   │   @ StringNode (location: (4,2)-(4,7))
-        │   │   │   │   ├── flags: ∅
+        │   │   │   │   ├── flags: frozen
         │   │   │   │   ├── opening_loc: (4,2)-(4,3) = "\""
         │   │   │   │   ├── content_loc: (4,3)-(4,6) = "foo"
         │   │   │   │   ├── closing_loc: (4,6)-(4,7) = "\""
@@ -75,7 +75,7 @@
         │   │   └── @ AssocNode (location: (4,16)-(4,29))
         │   │       ├── key:
         │   │       │   @ StringNode (location: (4,16)-(4,21))
-        │   │       │   ├── flags: ∅
+        │   │       │   ├── flags: frozen
         │   │       │   ├── opening_loc: (4,16)-(4,17) = "\""
         │   │       │   ├── content_loc: (4,17)-(4,20) = "bar"
         │   │       │   ├── closing_loc: (4,20)-(4,21) = "\""
@@ -184,7 +184,7 @@
         │   │   ├── @ AssocNode (location: (10,2)-(10,21))
         │   │   │   ├── key:
         │   │   │   │   @ StringNode (location: (10,2)-(10,7))
-        │   │   │   │   ├── flags: ∅
+        │   │   │   │   ├── flags: frozen
         │   │   │   │   ├── opening_loc: (10,2)-(10,3) = "\""
         │   │   │   │   ├── content_loc: (10,3)-(10,6) = "foo"
         │   │   │   │   ├── closing_loc: (10,6)-(10,7) = "\""
@@ -231,7 +231,7 @@
         │   │   ├── @ AssocNode (location: (13,2)-(13,14))
         │   │   │   ├── key:
         │   │   │   │   @ StringNode (location: (13,2)-(13,7))
-        │   │   │   │   ├── flags: ∅
+        │   │   │   │   ├── flags: frozen
         │   │   │   │   ├── opening_loc: (13,2)-(13,3) = "\""
         │   │   │   │   ├── content_loc: (13,3)-(13,6) = "foo"
         │   │   │   │   ├── closing_loc: (13,6)-(13,7) = "\""
diff --git a/test/prism/snapshots/unparser/corpus/literal/send.txt b/test/prism/snapshots/unparser/corpus/literal/send.txt
index 673787f1..2ddd55e5 100644
--- a/test/prism/snapshots/unparser/corpus/literal/send.txt
+++ b/test/prism/snapshots/unparser/corpus/literal/send.txt
@@ -1249,7 +1249,7 @@
         │   │   ├── flags: ∅
         │   │   └── arguments: (length: 1)
         │   │       └── @ KeywordHashNode (location: (63,8)-(63,16))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (63,8)-(63,16))
         │   │                   ├── key:
@@ -1310,7 +1310,7 @@
         │   │               └── @ AssocNode (location: (64,13)-(64,25))
         │   │                   ├── key:
         │   │                   │   @ StringNode (location: (64,13)-(64,18))
-        │   │                   │   ├── flags: ∅
+        │   │                   │   ├── flags: frozen
         │   │                   │   ├── opening_loc: (64,13)-(64,14) = "\""
         │   │                   │   ├── content_loc: (64,14)-(64,17) = "baz"
         │   │                   │   ├── closing_loc: (64,17)-(64,18) = "\""
@@ -1569,7 +1569,7 @@
         │   │   ├── flags: ∅
         │   │   └── arguments: (length: 1)
         │   │       └── @ KeywordHashNode (location: (70,4)-(70,8))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (70,4)-(70,8))
         │   │                   ├── key:
@@ -1615,7 +1615,7 @@
         │   │   ├── flags: ∅
         │   │   └── arguments: (length: 1)
         │   │       └── @ KeywordHashNode (location: (71,6)-(71,10))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (71,6)-(71,10))
         │   │                   ├── key:
diff --git a/test/prism/snapshots/whitequark/args_args_assocs.txt b/test/prism/snapshots/whitequark/args_args_assocs.txt
index 3d467e39..d5c0d7d1 100644
--- a/test/prism/snapshots/whitequark/args_args_assocs.txt
+++ b/test/prism/snapshots/whitequark/args_args_assocs.txt
@@ -25,7 +25,7 @@
         │   │       │   ├── closing_loc: ∅
         │   │       │   └── block: ∅
         │   │       └── @ KeywordHashNode (location: (1,9)-(1,18))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (1,9)-(1,18))
         │   │                   ├── key:
@@ -63,7 +63,7 @@
             │       │   ├── closing_loc: ∅
             │       │   └── block: ∅
             │       └── @ KeywordHashNode (location: (3,9)-(3,18))
-            │           ├── flags: symbol_keys
+            │           ├── flags: static_keys
             │           └── elements: (length: 1)
             │               └── @ AssocNode (location: (3,9)-(3,18))
             │                   ├── key:
diff --git a/test/prism/snapshots/whitequark/args_args_assocs_comma.txt b/test/prism/snapshots/whitequark/args_args_assocs_comma.txt
index 7b74a188..2aa16446 100644
--- a/test/prism/snapshots/whitequark/args_args_assocs_comma.txt
+++ b/test/prism/snapshots/whitequark/args_args_assocs_comma.txt
@@ -35,7 +35,7 @@
             │       │   ├── closing_loc: ∅
             │       │   └── block: ∅
             │       └── @ KeywordHashNode (location: (1,9)-(1,18))
-            │           ├── flags: symbol_keys
+            │           ├── flags: static_keys
             │           └── elements: (length: 1)
             │               └── @ AssocNode (location: (1,9)-(1,18))
             │                   ├── key:
diff --git a/test/prism/snapshots/whitequark/args_assocs.txt b/test/prism/snapshots/whitequark/args_assocs.txt
index e4acaca4..bf51dda1 100644
--- a/test/prism/snapshots/whitequark/args_assocs.txt
+++ b/test/prism/snapshots/whitequark/args_assocs.txt
@@ -15,7 +15,7 @@
         │   │   ├── flags: ∅
         │   │   └── arguments: (length: 1)
         │   │       └── @ KeywordHashNode (location: (1,4)-(1,13))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (1,4)-(1,13))
         │   │                   ├── key:
@@ -43,7 +43,7 @@
         │   │   ├── flags: ∅
         │   │   └── arguments: (length: 1)
         │   │       └── @ KeywordHashNode (location: (3,4)-(3,13))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (3,4)-(3,13))
         │   │                   ├── key:
@@ -95,7 +95,7 @@
         │   │       │   ├── closing_loc: ∅
         │   │       │   └── block: ∅
         │   │       └── @ KeywordHashNode (location: (5,14)-(5,21))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (5,14)-(5,21))
         │   │                   ├── key:
@@ -124,7 +124,7 @@
         │   │   ├── flags: ∅
         │   │   └── arguments: (length: 1)
         │   │       └── @ KeywordHashNode (location: (7,5)-(7,14))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (7,5)-(7,14))
         │   │                   ├── key:
@@ -148,7 +148,7 @@
         │   │   ├── flags: ∅
         │   │   └── arguments: (length: 1)
         │   │       └── @ KeywordHashNode (location: (9,6)-(9,16))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (9,6)-(9,16))
         │   │                   ├── key:
@@ -172,7 +172,7 @@
             │   ├── flags: ∅
             │   └── arguments: (length: 1)
             │       └── @ KeywordHashNode (location: (11,6)-(11,16))
-            │           ├── flags: symbol_keys
+            │           ├── flags: static_keys
             │           └── elements: (length: 1)
             │               └── @ AssocNode (location: (11,6)-(11,16))
             │                   ├── key:
diff --git a/test/prism/snapshots/whitequark/args_assocs_comma.txt b/test/prism/snapshots/whitequark/args_assocs_comma.txt
index 0ced5c7b..b98aa39c 100644
--- a/test/prism/snapshots/whitequark/args_assocs_comma.txt
+++ b/test/prism/snapshots/whitequark/args_assocs_comma.txt
@@ -25,7 +25,7 @@
             │   ├── flags: ∅
             │   └── arguments: (length: 1)
             │       └── @ KeywordHashNode (location: (1,4)-(1,13))
-            │           ├── flags: symbol_keys
+            │           ├── flags: static_keys
             │           └── elements: (length: 1)
             │               └── @ AssocNode (location: (1,4)-(1,13))
             │                   ├── key:
diff --git a/test/prism/snapshots/whitequark/args_assocs_legacy.txt b/test/prism/snapshots/whitequark/args_assocs_legacy.txt
index e4acaca4..bf51dda1 100644
--- a/test/prism/snapshots/whitequark/args_assocs_legacy.txt
+++ b/test/prism/snapshots/whitequark/args_assocs_legacy.txt
@@ -15,7 +15,7 @@
         │   │   ├── flags: ∅
         │   │   └── arguments: (length: 1)
         │   │       └── @ KeywordHashNode (location: (1,4)-(1,13))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (1,4)-(1,13))
         │   │                   ├── key:
@@ -43,7 +43,7 @@
         │   │   ├── flags: ∅
         │   │   └── arguments: (length: 1)
         │   │       └── @ KeywordHashNode (location: (3,4)-(3,13))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (3,4)-(3,13))
         │   │                   ├── key:
@@ -95,7 +95,7 @@
         │   │       │   ├── closing_loc: ∅
         │   │       │   └── block: ∅
         │   │       └── @ KeywordHashNode (location: (5,14)-(5,21))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (5,14)-(5,21))
         │   │                   ├── key:
@@ -124,7 +124,7 @@
         │   │   ├── flags: ∅
         │   │   └── arguments: (length: 1)
         │   │       └── @ KeywordHashNode (location: (7,5)-(7,14))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (7,5)-(7,14))
         │   │                   ├── key:
@@ -148,7 +148,7 @@
         │   │   ├── flags: ∅
         │   │   └── arguments: (length: 1)
         │   │       └── @ KeywordHashNode (location: (9,6)-(9,16))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (9,6)-(9,16))
         │   │                   ├── key:
@@ -172,7 +172,7 @@
             │   ├── flags: ∅
             │   └── arguments: (length: 1)
             │       └── @ KeywordHashNode (location: (11,6)-(11,16))
-            │           ├── flags: symbol_keys
+            │           ├── flags: static_keys
             │           └── elements: (length: 1)
             │               └── @ AssocNode (location: (11,6)-(11,16))
             │                   ├── key:
diff --git a/test/prism/snapshots/whitequark/bug_cmdarg.txt b/test/prism/snapshots/whitequark/bug_cmdarg.txt
index 428d061e..6779d117 100644
--- a/test/prism/snapshots/whitequark/bug_cmdarg.txt
+++ b/test/prism/snapshots/whitequark/bug_cmdarg.txt
@@ -15,7 +15,7 @@
         │   │   ├── flags: ∅
         │   │   └── arguments: (length: 1)
         │   │       └── @ KeywordHashNode (location: (1,7)-(1,15))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (1,7)-(1,15))
         │   │                   ├── key:
@@ -65,7 +65,7 @@
             │   ├── flags: ∅
             │   └── arguments: (length: 1)
             │       └── @ KeywordHashNode (location: (5,2)-(5,26))
-            │           ├── flags: symbol_keys
+            │           ├── flags: static_keys
             │           └── elements: (length: 1)
             │               └── @ AssocNode (location: (5,2)-(5,26))
             │                   ├── key:
diff --git a/test/prism/snapshots/whitequark/keyword_argument_omission.txt b/test/prism/snapshots/whitequark/keyword_argument_omission.txt
index afcfd87c..3ff3f9a1 100644
--- a/test/prism/snapshots/whitequark/keyword_argument_omission.txt
+++ b/test/prism/snapshots/whitequark/keyword_argument_omission.txt
@@ -15,7 +15,7 @@
             │   ├── flags: ∅
             │   └── arguments: (length: 1)
             │       └── @ KeywordHashNode (location: (1,4)-(1,10))
-            │           ├── flags: symbol_keys
+            │           ├── flags: static_keys
             │           └── elements: (length: 2)
             │               ├── @ AssocNode (location: (1,4)-(1,6))
             │               │   ├── key:
diff --git a/test/prism/snapshots/whitequark/newline_in_hash_argument.txt b/test/prism/snapshots/whitequark/newline_in_hash_argument.txt
index 5f5c1e40..0e036fbd 100644
--- a/test/prism/snapshots/whitequark/newline_in_hash_argument.txt
+++ b/test/prism/snapshots/whitequark/newline_in_hash_argument.txt
@@ -93,7 +93,7 @@
         │   │   ├── flags: ∅
         │   │   └── arguments: (length: 1)
         │   │       └── @ KeywordHashNode (location: (10,8)-(11,1))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (10,8)-(11,1))
         │   │                   ├── key:
@@ -131,7 +131,7 @@
             │   ├── flags: ∅
             │   └── arguments: (length: 1)
             │       └── @ KeywordHashNode (location: (13,8)-(14,1))
-            │           ├── flags: symbol_keys
+            │           ├── flags: static_keys
             │           └── elements: (length: 1)
             │               └── @ AssocNode (location: (13,8)-(14,1))
             │                   ├── key:
diff --git a/test/prism/snapshots/whitequark/parser_bug_525.txt b/test/prism/snapshots/whitequark/parser_bug_525.txt
index 7289bdf8..087cc76e 100644
--- a/test/prism/snapshots/whitequark/parser_bug_525.txt
+++ b/test/prism/snapshots/whitequark/parser_bug_525.txt
@@ -15,7 +15,7 @@
             │   ├── flags: ∅
             │   └── arguments: (length: 1)
             │       └── @ KeywordHashNode (location: (1,3)-(1,11))
-            │           ├── flags: symbol_keys
+            │           ├── flags: static_keys
             │           └── elements: (length: 1)
             │               └── @ AssocNode (location: (1,3)-(1,11))
             │                   ├── key:
diff --git a/test/prism/snapshots/whitequark/ruby_bug_11380.txt b/test/prism/snapshots/whitequark/ruby_bug_11380.txt
index 7ab13b89..cd2939f8 100644
--- a/test/prism/snapshots/whitequark/ruby_bug_11380.txt
+++ b/test/prism/snapshots/whitequark/ruby_bug_11380.txt
@@ -31,7 +31,7 @@
             │       │               ├── closing_loc: ∅
             │       │               └── unescaped: "hello"
             │       └── @ KeywordHashNode (location: (1,17)-(1,21))
-            │           ├── flags: symbol_keys
+            │           ├── flags: static_keys
             │           └── elements: (length: 1)
             │               └── @ AssocNode (location: (1,17)-(1,21))
             │                   ├── key:
diff --git a/test/prism/snapshots/whitequark/ruby_bug_12073.txt b/test/prism/snapshots/whitequark/ruby_bug_12073.txt
index 27f2838b..521df7a0 100644
--- a/test/prism/snapshots/whitequark/ruby_bug_12073.txt
+++ b/test/prism/snapshots/whitequark/ruby_bug_12073.txt
@@ -23,7 +23,7 @@
         │   │   ├── flags: ∅
         │   │   └── arguments: (length: 1)
         │   │       └── @ KeywordHashNode (location: (1,9)-(1,13))
-        │   │           ├── flags: symbol_keys
+        │   │           ├── flags: static_keys
         │   │           └── elements: (length: 1)
         │   │               └── @ AssocNode (location: (1,9)-(1,13))
         │   │                   ├── key: