Repository: ruby/prism
Pull request #1755 (2023-10-31 20:03:10)

Split KeywordParameterNode into Optional and Required
Prior to this commit, KeywordParameterNode included both optional and required keywords. With this commit, it is split in two, with `OptionalKeywordParameterNode`s no longer having a value field.

The main motivation behind this change is to remain consistent with Prism's verbose types, and indicate the information known at parsing time which distinguishes these two node types. It will also lead to a minor memory save as `OptionalKeywordParameterNode`s no longer have empty `value` fields.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9130f9a9..d1de2e07 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
 
 ## [Unreleased]
 
+### Changed
+
+- **BREAKING**: `KeywordParameterNode` is split into `OptionalKeywordParameterNode` and `RequiredKeywordParameterNode`. `RequiredKeywordParameterNode` has no `value` field.
+
 ## [0.16.0] - 2023-10-30
 
 ### Added
diff --git a/config.yml b/config.yml
index 2e605ae5..3446e277 100644
--- a/config.yml
+++ b/config.yml
@@ -1692,24 +1692,6 @@ nodes:
 
           foo(a: b)
               ^^^^
-  - name: KeywordParameterNode
-    fields:
-      - name: name
-        type: constant
-      - name: name_loc
-        type: location
-      - name: value
-        type: node?
-    comment: |
-      Represents a keyword parameter to a method, block, or lambda definition.
-
-          def a(b:)
-                ^^
-          end
-
-          def a(b: 1)
-                ^^^^
-          end
   - name: KeywordRestParameterNode
     fields:
       - name: name
@@ -1997,6 +1979,20 @@ nodes:
 
           $1
           ^^
+  - name: OptionalKeywordParameterNode
+    fields:
+      - name: name
+        type: constant
+      - name: name_loc
+        type: location
+      - name: value
+        type: node
+    comment: |
+      Represents an optional keyword parameter to a method, block, or lambda definition.
+
+          def a(b: 1)
+                ^^^^
+          end
   - name: OptionalParameterNode
     fields:
       - name: name
@@ -2184,6 +2180,18 @@ nodes:
 
           /foo/i
           ^^^^^^
+  - name: RequiredKeywordParameterNode
+    fields:
+      - name: name
+        type: constant
+      - name: name_loc
+        type: location
+    comment: |
+      Represents a required keyword parameter to a method, block, or lambda definition.
+
+          def a(b: )
+                ^^
+          end
   - name: RequiredParameterNode
     fields:
       - name: name
diff --git a/lib/prism/debug.rb b/lib/prism/debug.rb
index cdb8e9b3..bd2eb084 100644
--- a/lib/prism/debug.rb
+++ b/lib/prism/debug.rb
@@ -114,8 +114,8 @@ module Prism
                   AnonymousLocal
                 end
               end,
-              *params.keywords.reject(&:value).map(&:name),
-              *params.keywords.select(&:value).map(&:name)
+              *params.keywords.grep(RequiredKeywordParameterNode).map(&:name),
+              *params.keywords.grep(OptionalKeywordParameterNode).map(&:name),
             ]
 
             sorted << AnonymousLocal if params.keywords.any?
diff --git a/src/prism.c b/src/prism.c
index 7e5d3e48..e6639314 100644
--- a/src/prism.c
+++ b/src/prism.c
@@ -3326,17 +3326,37 @@ pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *el
     hash->base.location.end = element->location.end;
 }
 
-// Allocate a new KeywordParameterNode node.
-static pm_keyword_parameter_node_t *
-pm_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
-    pm_keyword_parameter_node_t *node = PM_ALLOC_NODE(parser, pm_keyword_parameter_node_t);
+// Allocate a new RequiredKeywordParameterNode node.
+static pm_required_keyword_parameter_node_t *
+pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
+    pm_required_keyword_parameter_node_t *node = PM_ALLOC_NODE(parser, pm_required_keyword_parameter_node_t);
 
-    *node = (pm_keyword_parameter_node_t) {
+    *node = (pm_required_keyword_parameter_node_t) {
         {
-            .type = PM_KEYWORD_PARAMETER_NODE,
+            .type = PM_REQUIRED_KEYWORD_PARAMETER_NODE,
             .location = {
                 .start = name->start,
-                .end = value == NULL ? name->end : value->location.end
+                .end = name->end
+            },
+        },
+        .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
+        .name_loc = PM_LOCATION_TOKEN_VALUE(name),
+    };
+
+    return node;
+}
+
+// Allocate a new OptionalKeywordParameterNode node.
+static pm_optional_keyword_parameter_node_t *
+pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
+    pm_optional_keyword_parameter_node_t *node = PM_ALLOC_NODE(parser, pm_optional_keyword_parameter_node_t);
+
+    *node = (pm_optional_keyword_parameter_node_t) {
+        {
+            .type = PM_OPTIONAL_KEYWORD_PARAMETER_NODE,
+            .location = {
+                .start = name->start,
+                .end = value->location.end
             },
         },
         .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
@@ -10482,7 +10502,7 @@ parse_parameters(
                     case PM_TOKEN_COMMA:
                     case PM_TOKEN_PARENTHESIS_RIGHT:
                     case PM_TOKEN_PIPE: {
-                        pm_node_t *param = (pm_node_t *) pm_keyword_parameter_node_create(parser, &name, NULL);
+                        pm_node_t *param = (pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
                         pm_parameters_node_keywords_append(params, param);
                         break;
                     }
@@ -10493,19 +10513,23 @@ parse_parameters(
                             break;
                         }
 
-                        pm_node_t *param = (pm_node_t *) pm_keyword_parameter_node_create(parser, &name, NULL);
+                        pm_node_t *param = (pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
                         pm_parameters_node_keywords_append(params, param);
                         break;
                     }
                     default: {
-                        pm_node_t *value = NULL;
+                        pm_node_t *param;
+
                         if (token_begins_expression_p(parser->current.type)) {
                             context_push(parser, PM_CONTEXT_DEFAULT_PARAMS);
-                            value = parse_expression(parser, binding_power, PM_ERR_PARAMETER_NO_DEFAULT_KW);
+                            pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_PARAMETER_NO_DEFAULT_KW);
                             context_pop(parser);
+                            param = (pm_node_t *) pm_optional_keyword_parameter_node_create(parser, &name, value);
+                        }
+                        else {
+                            param = (pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
                         }
 
-                        pm_node_t *param = (pm_node_t *) pm_keyword_parameter_node_create(parser, &name, value);
                         pm_parameters_node_keywords_append(params, param);
 
                         // If parsing the value of the parameter resulted in error recovery,


Test patch:
diff --git a/test/prism/errors_test.rb b/test/prism/errors_test.rb
index e08c2f74..726bb143 100644
--- a/test/prism/errors_test.rb
+++ b/test/prism/errors_test.rb
@@ -746,7 +746,7 @@ module Prism
           [],
           nil,
           [RequiredParameterNode(:a)],
-          [KeywordParameterNode(:b, Location(), nil)],
+          [RequiredKeywordParameterNode(:b, Location())],
           nil,
           nil
         ),
@@ -774,7 +774,7 @@ module Prism
           [],
           nil,
           [],
-          [KeywordParameterNode(:b, Location(), nil)],
+          [RequiredKeywordParameterNode(:b, Location())],
           KeywordRestParameterNode(:rest, Location(), Location()),
           nil
         ),
@@ -824,7 +824,7 @@ module Prism
           [],
           nil,
           [RequiredParameterNode(:a)],
-          [KeywordParameterNode(:b, Location(), nil)],
+          [RequiredKeywordParameterNode(:b, Location())],
           KeywordRestParameterNode(:args, Location(), Location()),
           nil
         ),
@@ -854,7 +854,7 @@ module Prism
           [],
           nil,
           [RequiredParameterNode(:a)],
-          [KeywordParameterNode(:b, Location(), nil)],
+          [RequiredKeywordParameterNode(:b, Location())],
           KeywordRestParameterNode(:args, Location(), Location()),
           nil
         ),
@@ -884,7 +884,7 @@ module Prism
           [],
           nil,
           [RequiredParameterNode(:a)],
-          [KeywordParameterNode(:b, Location(), nil)],
+          [RequiredKeywordParameterNode(:b, Location())],
           KeywordRestParameterNode(:args, Location(), Location()),
           nil
         ),
diff --git a/test/prism/location_test.rb b/test/prism/location_test.rb
index 5501d9de..363e96fa 100644
--- a/test/prism/location_test.rb
+++ b/test/prism/location_test.rb
@@ -502,16 +502,6 @@ module Prism
       assert_location(KeywordHashNode, "foo(a, b: 1)", 7...11) { |node| node.arguments.arguments[1] }
     end
 
-    def test_KeywordParameterNode
-      assert_location(KeywordParameterNode, "def foo(bar:); end", 8...12) do |node|
-        node.parameters.keywords.first
-      end
-
-      assert_location(KeywordParameterNode, "def foo(bar: nil); end", 8...16) do |node|
-        node.parameters.keywords.first
-      end
-    end
-
     def test_KeywordRestParameterNode
       assert_location(KeywordRestParameterNode, "def foo(**); end", 8...10) do |node|
         node.parameters.keyword_rest
@@ -609,6 +599,12 @@ module Prism
       assert_location(NumberedReferenceReadNode, "$1")
     end
 
+    def test_OptionalKeywordParameterNode
+      assert_location(OptionalKeywordParameterNode, "def foo(bar: nil); end", 8...16) do |node|
+        node.parameters.keywords.first
+      end
+    end
+
     def test_OptionalParameterNode
       assert_location(OptionalParameterNode, "def foo(bar = nil); end", 8...17) do |node|
         node.parameters.optionals.first
@@ -673,6 +669,12 @@ module Prism
       assert_location(RegularExpressionNode, "/foo/")
     end
 
+    def test_RequiredKeywordParameterNode
+      assert_location(RequiredKeywordParameterNode, "def foo(bar:); end", 8...12) do |node|
+        node.parameters.keywords.first
+      end
+    end
+
     def test_RequiredParameterNode
       assert_location(RequiredParameterNode, "def foo(bar); end", 8...11) do |node|
         node.parameters.requireds.first
diff --git a/test/prism/snapshots/blocks.txt b/test/prism/snapshots/blocks.txt
index 91a07359..9769e9e4 100644
--- a/test/prism/snapshots/blocks.txt
+++ b/test/prism/snapshots/blocks.txt
@@ -517,10 +517,9 @@
         │   │   │   │   ├── rest: ∅
         │   │   │   │   ├── posts: (length: 0)
         │   │   │   │   ├── keywords: (length: 1)
-        │   │   │   │   │   └── @ KeywordParameterNode (location: (33,17)-(33,19))
+        │   │   │   │   │   └── @ RequiredKeywordParameterNode (location: (33,17)-(33,19))
         │   │   │   │   │       ├── name: :z
-        │   │   │   │   │       ├── name_loc: (33,17)-(33,19) = "z:"
-        │   │   │   │   │       └── value: ∅
+        │   │   │   │   │       └── name_loc: (33,17)-(33,19) = "z:"
         │   │   │   │   ├── keyword_rest: ∅
         │   │   │   │   └── block: ∅
         │   │   │   ├── locals: (length: 0)
@@ -696,13 +695,13 @@
         │   │   │       │   │   │   ├── rest: ∅
         │   │   │       │   │   │   ├── posts: (length: 0)
         │   │   │       │   │   │   ├── keywords: (length: 2)
-        │   │   │       │   │   │   │   ├── @ KeywordParameterNode (location: (49,2)-(49,6))
+        │   │   │       │   │   │   │   ├── @ OptionalKeywordParameterNode (location: (49,2)-(49,6))
         │   │   │       │   │   │   │   │   ├── name: :a
         │   │   │       │   │   │   │   │   ├── name_loc: (49,2)-(49,4) = "a:"
         │   │   │       │   │   │   │   │   └── value:
         │   │   │       │   │   │   │   │       @ IntegerNode (location: (49,5)-(49,6))
         │   │   │       │   │   │   │   │       └── flags: decimal
-        │   │   │       │   │   │   │   └── @ KeywordParameterNode (location: (50,2)-(50,6))
+        │   │   │       │   │   │   │   └── @ OptionalKeywordParameterNode (location: (50,2)-(50,6))
         │   │   │       │   │   │   │       ├── name: :b
         │   │   │       │   │   │   │       ├── name_loc: (50,2)-(50,4) = "b:"
         │   │   │       │   │   │   │       └── value:
diff --git a/test/prism/snapshots/lambda.txt b/test/prism/snapshots/lambda.txt
index 380284b5..270594d7 100644
--- a/test/prism/snapshots/lambda.txt
+++ b/test/prism/snapshots/lambda.txt
@@ -39,7 +39,7 @@
         │   │   │   ├── rest: ∅
         │   │   │   ├── posts: (length: 0)
         │   │   │   ├── keywords: (length: 1)
-        │   │   │   │   └── @ KeywordParameterNode (location: (5,3)-(5,13))
+        │   │   │   │   └── @ OptionalKeywordParameterNode (location: (5,3)-(5,13))
         │   │   │   │       ├── name: :x
         │   │   │   │       ├── name_loc: (5,3)-(5,5) = "x:"
         │   │   │   │       └── value:
@@ -89,7 +89,7 @@
         │   │   │   ├── rest: ∅
         │   │   │   ├── posts: (length: 0)
         │   │   │   ├── keywords: (length: 1)
-        │   │   │   │   └── @ KeywordParameterNode (location: (7,3)-(7,11))
+        │   │   │   │   └── @ OptionalKeywordParameterNode (location: (7,3)-(7,11))
         │   │   │   │       ├── name: :a
         │   │   │   │       ├── name_loc: (7,3)-(7,5) = "a:"
         │   │   │   │       └── value:
@@ -173,7 +173,7 @@
             │   │   ├── rest: ∅
             │   │   ├── posts: (length: 0)
             │   │   ├── keywords: (length: 1)
-            │   │   │   └── @ KeywordParameterNode (location: (11,3)-(11,11))
+            │   │   │   └── @ OptionalKeywordParameterNode (location: (11,3)-(11,11))
             │   │   │       ├── name: :foo
             │   │   │       ├── name_loc: (11,3)-(11,7) = "foo:"
             │   │   │       └── value:
diff --git a/test/prism/snapshots/methods.txt b/test/prism/snapshots/methods.txt
index c4f2a085..ebaeb839 100644
--- a/test/prism/snapshots/methods.txt
+++ b/test/prism/snapshots/methods.txt
@@ -260,10 +260,9 @@
         │   │   ├── rest: ∅
         │   │   ├── posts: (length: 0)
         │   │   ├── keywords: (length: 1)
-        │   │   │   └── @ KeywordParameterNode (location: (31,6)-(31,8))
+        │   │   │   └── @ RequiredKeywordParameterNode (location: (31,6)-(31,8))
         │   │   │       ├── name: :b
-        │   │   │       ├── name_loc: (31,6)-(31,8) = "b:"
-        │   │   │       └── value: ∅
+        │   │   │       └── name_loc: (31,6)-(31,8) = "b:"
         │   │   ├── keyword_rest: ∅
         │   │   └── block: ∅
         │   ├── body: ∅
@@ -291,10 +290,9 @@
         │   │   ├── rest: ∅
         │   │   ├── posts: (length: 0)
         │   │   ├── keywords: (length: 1)
-        │   │   │   └── @ KeywordParameterNode (location: (35,6)-(35,8))
+        │   │   │   └── @ RequiredKeywordParameterNode (location: (35,6)-(35,8))
         │   │   │       ├── name: :b
-        │   │   │       ├── name_loc: (35,6)-(35,8) = "b:"
-        │   │   │       └── value: ∅
+        │   │   │       └── name_loc: (35,6)-(35,8) = "b:"
         │   │   ├── keyword_rest: ∅
         │   │   └── block: ∅
         │   ├── body: ∅
@@ -428,11 +426,10 @@
         │   │   ├── rest: ∅
         │   │   ├── posts: (length: 0)
         │   │   ├── keywords: (length: 2)
-        │   │   │   ├── @ KeywordParameterNode (location: (53,6)-(53,8))
+        │   │   │   ├── @ RequiredKeywordParameterNode (location: (53,6)-(53,8))
         │   │   │   │   ├── name: :b
-        │   │   │   │   ├── name_loc: (53,6)-(53,8) = "b:"
-        │   │   │   │   └── value: ∅
-        │   │   │   └── @ KeywordParameterNode (location: (53,10)-(53,14))
+        │   │   │   │   └── name_loc: (53,6)-(53,8) = "b:"
+        │   │   │   └── @ OptionalKeywordParameterNode (location: (53,10)-(53,14))
         │   │   │       ├── name: :c
         │   │   │       ├── name_loc: (53,10)-(53,12) = "c:"
         │   │   │       └── value:
@@ -459,11 +456,10 @@
         │   │   ├── rest: ∅
         │   │   ├── posts: (length: 0)
         │   │   ├── keywords: (length: 2)
-        │   │   │   ├── @ KeywordParameterNode (location: (56,6)-(56,8))
+        │   │   │   ├── @ RequiredKeywordParameterNode (location: (56,6)-(56,8))
         │   │   │   │   ├── name: :b
-        │   │   │   │   ├── name_loc: (56,6)-(56,8) = "b:"
-        │   │   │   │   └── value: ∅
-        │   │   │   └── @ KeywordParameterNode (location: (56,10)-(56,14))
+        │   │   │   │   └── name_loc: (56,6)-(56,8) = "b:"
+        │   │   │   └── @ OptionalKeywordParameterNode (location: (56,10)-(56,14))
         │   │   │       ├── name: :c
         │   │   │       ├── name_loc: (56,10)-(56,12) = "c:"
         │   │   │       └── value:
@@ -490,16 +486,15 @@
         │   │   ├── rest: ∅
         │   │   ├── posts: (length: 0)
         │   │   ├── keywords: (length: 2)
-        │   │   │   ├── @ KeywordParameterNode (location: (59,6)-(60,3))
+        │   │   │   ├── @ OptionalKeywordParameterNode (location: (59,6)-(60,3))
         │   │   │   │   ├── name: :b
         │   │   │   │   ├── name_loc: (59,6)-(59,8) = "b:"
         │   │   │   │   └── value:
         │   │   │   │       @ IntegerNode (location: (60,2)-(60,3))
         │   │   │   │       └── flags: decimal
-        │   │   │   └── @ KeywordParameterNode (location: (60,5)-(60,7))
+        │   │   │   └── @ RequiredKeywordParameterNode (location: (60,5)-(60,7))
         │   │   │       ├── name: :c
-        │   │   │       ├── name_loc: (60,5)-(60,7) = "c:"
-        │   │   │       └── value: ∅
+        │   │   │       └── name_loc: (60,5)-(60,7) = "c:"
         │   │   ├── keyword_rest: ∅
         │   │   └── block: ∅
         │   ├── body: ∅
@@ -1312,7 +1307,7 @@
         │   │   ├── rest: ∅
         │   │   ├── posts: (length: 0)
         │   │   ├── keywords: (length: 1)
-        │   │   │   └── @ KeywordParameterNode (location: (142,8)-(142,19))
+        │   │   │   └── @ OptionalKeywordParameterNode (location: (142,8)-(142,19))
         │   │   │       ├── name: :a
         │   │   │       ├── name_loc: (142,8)-(142,10) = "a:"
         │   │   │       └── value:
@@ -1352,7 +1347,7 @@
         │   │   ├── rest: ∅
         │   │   ├── posts: (length: 0)
         │   │   ├── keywords: (length: 1)
-        │   │   │   └── @ KeywordParameterNode (location: (145,8)-(145,18))
+        │   │   │   └── @ OptionalKeywordParameterNode (location: (145,8)-(145,18))
         │   │   │       ├── name: :a
         │   │   │       ├── name_loc: (145,8)-(145,10) = "a:"
         │   │   │       └── value:
@@ -1390,7 +1385,7 @@
         │   │   ├── rest: ∅
         │   │   ├── posts: (length: 0)
         │   │   ├── keywords: (length: 1)
-        │   │   │   └── @ KeywordParameterNode (location: (148,8)-(148,17))
+        │   │   │   └── @ OptionalKeywordParameterNode (location: (148,8)-(148,17))
         │   │   │       ├── name: :a
         │   │   │       ├── name_loc: (148,8)-(148,10) = "a:"
         │   │   │       └── value:
diff --git a/test/prism/snapshots/procs.txt b/test/prism/snapshots/procs.txt
index a711c555..c29c39fe 100644
--- a/test/prism/snapshots/procs.txt
+++ b/test/prism/snapshots/procs.txt
@@ -144,14 +144,12 @@
         │   │   │   ├── rest: ∅
         │   │   │   ├── posts: (length: 0)
         │   │   │   ├── keywords: (length: 2)
-        │   │   │   │   ├── @ KeywordParameterNode (location: (17,13)-(17,15))
+        │   │   │   │   ├── @ RequiredKeywordParameterNode (location: (17,13)-(17,15))
         │   │   │   │   │   ├── name: :c
-        │   │   │   │   │   ├── name_loc: (17,13)-(17,15) = "c:"
-        │   │   │   │   │   └── value: ∅
-        │   │   │   │   └── @ KeywordParameterNode (location: (17,17)-(17,19))
+        │   │   │   │   │   └── name_loc: (17,13)-(17,15) = "c:"
+        │   │   │   │   └── @ RequiredKeywordParameterNode (location: (17,17)-(17,19))
         │   │   │   │       ├── name: :d
-        │   │   │   │       ├── name_loc: (17,17)-(17,19) = "d:"
-        │   │   │   │       └── value: ∅
+        │   │   │   │       └── name_loc: (17,17)-(17,19) = "d:"
         │   │   │   ├── keyword_rest: ∅
         │   │   │   └── block:
         │   │   │       @ BlockParameterNode (location: (17,21)-(17,23))
@@ -194,14 +192,12 @@
         │   │   │   │   └── operator_loc: (19,14)-(19,15) = "*"
         │   │   │   ├── posts: (length: 0)
         │   │   │   ├── keywords: (length: 2)
-        │   │   │   │   ├── @ KeywordParameterNode (location: (19,18)-(19,20))
+        │   │   │   │   ├── @ RequiredKeywordParameterNode (location: (19,18)-(19,20))
         │   │   │   │   │   ├── name: :d
-        │   │   │   │   │   ├── name_loc: (19,18)-(19,20) = "d:"
-        │   │   │   │   │   └── value: ∅
-        │   │   │   │   └── @ KeywordParameterNode (location: (19,22)-(19,24))
+        │   │   │   │   │   └── name_loc: (19,18)-(19,20) = "d:"
+        │   │   │   │   └── @ RequiredKeywordParameterNode (location: (19,22)-(19,24))
         │   │   │   │       ├── name: :e
-        │   │   │   │       ├── name_loc: (19,22)-(19,24) = "e:"
-        │   │   │   │       └── value: ∅
+        │   │   │   │       └── name_loc: (19,22)-(19,24) = "e:"
         │   │   │   ├── keyword_rest:
         │   │   │   │   @ KeywordRestParameterNode (location: (19,26)-(19,29))
         │   │   │   │   ├── name: :f
@@ -248,14 +244,12 @@
         │   │   │   │   └── operator_loc: (21,14)-(21,15) = "*"
         │   │   │   ├── posts: (length: 0)
         │   │   │   ├── keywords: (length: 2)
-        │   │   │   │   ├── @ KeywordParameterNode (location: (21,18)-(21,20))
+        │   │   │   │   ├── @ RequiredKeywordParameterNode (location: (21,18)-(21,20))
         │   │   │   │   │   ├── name: :d
-        │   │   │   │   │   ├── name_loc: (21,18)-(21,20) = "d:"
-        │   │   │   │   │   └── value: ∅
-        │   │   │   │   └── @ KeywordParameterNode (location: (21,22)-(21,24))
+        │   │   │   │   │   └── name_loc: (21,18)-(21,20) = "d:"
+        │   │   │   │   └── @ RequiredKeywordParameterNode (location: (21,22)-(21,24))
         │   │   │   │       ├── name: :e
-        │   │   │   │       ├── name_loc: (21,22)-(21,24) = "e:"
-        │   │   │   │       └── value: ∅
+        │   │   │   │       └── name_loc: (21,22)-(21,24) = "e:"
         │   │   │   ├── keyword_rest:
         │   │   │   │   @ KeywordRestParameterNode (location: (21,26)-(21,29))
         │   │   │   │   ├── name: :f
diff --git a/test/prism/snapshots/seattlerb/args_kw_block.txt b/test/prism/snapshots/seattlerb/args_kw_block.txt
index 3cbd2c17..8d4bc2be 100644
--- a/test/prism/snapshots/seattlerb/args_kw_block.txt
+++ b/test/prism/snapshots/seattlerb/args_kw_block.txt
@@ -14,7 +14,7 @@
             │   ├── rest: ∅
             │   ├── posts: (length: 0)
             │   ├── keywords: (length: 1)
-            │   │   └── @ KeywordParameterNode (location: (1,6)-(1,10))
+            │   │   └── @ OptionalKeywordParameterNode (location: (1,6)-(1,10))
             │   │       ├── name: :a
             │   │       ├── name_loc: (1,6)-(1,8) = "a:"
             │   │       └── value:
diff --git a/test/prism/snapshots/seattlerb/block_kw.txt b/test/prism/snapshots/seattlerb/block_kw.txt
index 92773bda..629a8808 100644
--- a/test/prism/snapshots/seattlerb/block_kw.txt
+++ b/test/prism/snapshots/seattlerb/block_kw.txt
@@ -22,7 +22,7 @@
             │   │   │   ├── rest: ∅
             │   │   │   ├── posts: (length: 0)
             │   │   │   ├── keywords: (length: 1)
-            │   │   │   │   └── @ KeywordParameterNode (location: (1,8)-(1,12))
+            │   │   │   │   └── @ OptionalKeywordParameterNode (location: (1,8)-(1,12))
             │   │   │   │       ├── name: :k
             │   │   │   │       ├── name_loc: (1,8)-(1,10) = "k:"
             │   │   │   │       └── value:
diff --git a/test/prism/snapshots/seattlerb/block_kw__required.txt b/test/prism/snapshots/seattlerb/block_kw__required.txt
index 7e0ad49f..10ae4f5a 100644
--- a/test/prism/snapshots/seattlerb/block_kw__required.txt
+++ b/test/prism/snapshots/seattlerb/block_kw__required.txt
@@ -22,10 +22,9 @@
             │   │   │   ├── rest: ∅
             │   │   │   ├── posts: (length: 0)
             │   │   │   ├── keywords: (length: 1)
-            │   │   │   │   └── @ KeywordParameterNode (location: (1,9)-(1,11))
+            │   │   │   │   └── @ RequiredKeywordParameterNode (location: (1,9)-(1,11))
             │   │   │   │       ├── name: :k
-            │   │   │   │       ├── name_loc: (1,9)-(1,11) = "k:"
-            │   │   │   │       └── value: ∅
+            │   │   │   │       └── name_loc: (1,9)-(1,11) = "k:"
             │   │   │   ├── keyword_rest: ∅
             │   │   │   └── block: ∅
             │   │   ├── locals: (length: 0)
diff --git a/test/prism/snapshots/seattlerb/block_kwarg_lvar.txt b/test/prism/snapshots/seattlerb/block_kwarg_lvar.txt
index 434c1a4f..83254370 100644
--- a/test/prism/snapshots/seattlerb/block_kwarg_lvar.txt
+++ b/test/prism/snapshots/seattlerb/block_kwarg_lvar.txt
@@ -22,7 +22,7 @@
             │   │   │   ├── rest: ∅
             │   │   │   ├── posts: (length: 0)
             │   │   │   ├── keywords: (length: 1)
-            │   │   │   │   └── @ KeywordParameterNode (location: (1,6)-(1,14))
+            │   │   │   │   └── @ OptionalKeywordParameterNode (location: (1,6)-(1,14))
             │   │   │   │       ├── name: :kw
             │   │   │   │       ├── name_loc: (1,6)-(1,9) = "kw:"
             │   │   │   │       └── value:
diff --git a/test/prism/snapshots/seattlerb/block_kwarg_lvar_multiple.txt b/test/prism/snapshots/seattlerb/block_kwarg_lvar_multiple.txt
index badb88d7..9c9d0853 100644
--- a/test/prism/snapshots/seattlerb/block_kwarg_lvar_multiple.txt
+++ b/test/prism/snapshots/seattlerb/block_kwarg_lvar_multiple.txt
@@ -22,7 +22,7 @@
             │   │   │   ├── rest: ∅
             │   │   │   ├── posts: (length: 0)
             │   │   │   ├── keywords: (length: 2)
-            │   │   │   │   ├── @ KeywordParameterNode (location: (1,6)-(1,14))
+            │   │   │   │   ├── @ OptionalKeywordParameterNode (location: (1,6)-(1,14))
             │   │   │   │   │   ├── name: :kw
             │   │   │   │   │   ├── name_loc: (1,6)-(1,9) = "kw:"
             │   │   │   │   │   └── value:
@@ -31,7 +31,7 @@
             │   │   │   │   │       ├── value_loc: (1,11)-(1,14) = "val"
             │   │   │   │   │       ├── closing_loc: ∅
             │   │   │   │   │       └── unescaped: "val"
-            │   │   │   │   └── @ KeywordParameterNode (location: (1,16)-(1,26))
+            │   │   │   │   └── @ OptionalKeywordParameterNode (location: (1,16)-(1,26))
             │   │   │   │       ├── name: :kw2
             │   │   │   │       ├── name_loc: (1,16)-(1,20) = "kw2:"
             │   │   │   │       └── value:
diff --git a/test/prism/snapshots/seattlerb/defn_kwarg_kwarg.txt b/test/prism/snapshots/seattlerb/defn_kwarg_kwarg.txt
index 2d57ad31..4ca746c2 100644
--- a/test/prism/snapshots/seattlerb/defn_kwarg_kwarg.txt
+++ b/test/prism/snapshots/seattlerb/defn_kwarg_kwarg.txt
@@ -16,13 +16,13 @@
             │   ├── rest: ∅
             │   ├── posts: (length: 0)
             │   ├── keywords: (length: 2)
-            │   │   ├── @ KeywordParameterNode (location: (1,9)-(1,13))
+            │   │   ├── @ OptionalKeywordParameterNode (location: (1,9)-(1,13))
             │   │   │   ├── name: :b
             │   │   │   ├── name_loc: (1,9)-(1,11) = "b:"
             │   │   │   └── value:
             │   │   │       @ IntegerNode (location: (1,12)-(1,13))
             │   │   │       └── flags: decimal
-            │   │   └── @ KeywordParameterNode (location: (1,15)-(1,19))
+            │   │   └── @ OptionalKeywordParameterNode (location: (1,15)-(1,19))
             │   │       ├── name: :c
             │   │       ├── name_loc: (1,15)-(1,17) = "c:"
             │   │       └── value:
diff --git a/test/prism/snapshots/seattlerb/defn_kwarg_kwsplat.txt b/test/prism/snapshots/seattlerb/defn_kwarg_kwsplat.txt
index 0d005c20..5356f731 100644
--- a/test/prism/snapshots/seattlerb/defn_kwarg_kwsplat.txt
+++ b/test/prism/snapshots/seattlerb/defn_kwarg_kwsplat.txt
@@ -14,7 +14,7 @@
             │   ├── rest: ∅
             │   ├── posts: (length: 0)
             │   ├── keywords: (length: 1)
-            │   │   └── @ KeywordParameterNode (location: (1,6)-(1,10))
+            │   │   └── @ OptionalKeywordParameterNode (location: (1,6)-(1,10))
             │   │       ├── name: :b
             │   │       ├── name_loc: (1,6)-(1,8) = "b:"
             │   │       └── value:
diff --git a/test/prism/snapshots/seattlerb/defn_kwarg_kwsplat_anon.txt b/test/prism/snapshots/seattlerb/defn_kwarg_kwsplat_anon.txt
index daa6c6bb..4ccf1907 100644
--- a/test/prism/snapshots/seattlerb/defn_kwarg_kwsplat_anon.txt
+++ b/test/prism/snapshots/seattlerb/defn_kwarg_kwsplat_anon.txt
@@ -14,7 +14,7 @@
             │   ├── rest: ∅
             │   ├── posts: (length: 0)
             │   ├── keywords: (length: 1)
-            │   │   └── @ KeywordParameterNode (location: (1,6)-(1,10))
+            │   │   └── @ OptionalKeywordParameterNode (location: (1,6)-(1,10))
             │   │       ├── name: :b
             │   │       ├── name_loc: (1,6)-(1,8) = "b:"
             │   │       └── value:
diff --git a/test/prism/snapshots/seattlerb/defn_kwarg_lvar.txt b/test/prism/snapshots/seattlerb/defn_kwarg_lvar.txt
index 6b46d9e2..435c2f22 100644
--- a/test/prism/snapshots/seattlerb/defn_kwarg_lvar.txt
+++ b/test/prism/snapshots/seattlerb/defn_kwarg_lvar.txt
@@ -14,7 +14,7 @@
             │   ├── rest: ∅
             │   ├── posts: (length: 0)
             │   ├── keywords: (length: 1)
-            │   │   └── @ KeywordParameterNode (location: (1,8)-(1,16))
+            │   │   └── @ OptionalKeywordParameterNode (location: (1,8)-(1,16))
             │   │       ├── name: :kw
             │   │       ├── name_loc: (1,8)-(1,11) = "kw:"
             │   │       └── value:
diff --git a/test/prism/snapshots/seattlerb/defn_kwarg_no_parens.txt b/test/prism/snapshots/seattlerb/defn_kwarg_no_parens.txt
index ba0bd443..6905bd19 100644
--- a/test/prism/snapshots/seattlerb/defn_kwarg_no_parens.txt
+++ b/test/prism/snapshots/seattlerb/defn_kwarg_no_parens.txt
@@ -14,7 +14,7 @@
             │   ├── rest: ∅
             │   ├── posts: (length: 0)
             │   ├── keywords: (length: 1)
-            │   │   └── @ KeywordParameterNode (location: (1,6)-(1,10))
+            │   │   └── @ OptionalKeywordParameterNode (location: (1,6)-(1,10))
             │   │       ├── name: :a
             │   │       ├── name_loc: (1,6)-(1,8) = "a:"
             │   │       └── value:
diff --git a/test/prism/snapshots/seattlerb/defn_kwarg_val.txt b/test/prism/snapshots/seattlerb/defn_kwarg_val.txt
index 5933c969..772c7b62 100644
--- a/test/prism/snapshots/seattlerb/defn_kwarg_val.txt
+++ b/test/prism/snapshots/seattlerb/defn_kwarg_val.txt
@@ -16,7 +16,7 @@
             │   ├── rest: ∅
             │   ├── posts: (length: 0)
             │   ├── keywords: (length: 1)
-            │   │   └── @ KeywordParameterNode (location: (1,9)-(1,12))
+            │   │   └── @ OptionalKeywordParameterNode (location: (1,9)-(1,12))
             │   │       ├── name: :b
             │   │       ├── name_loc: (1,9)-(1,11) = "b:"
             │   │       └── value:
diff --git a/test/prism/snapshots/seattlerb/defs_kwarg.txt b/test/prism/snapshots/seattlerb/defs_kwarg.txt
index 8343c1f1..62571e86 100644
--- a/test/prism/snapshots/seattlerb/defs_kwarg.txt
+++ b/test/prism/snapshots/seattlerb/defs_kwarg.txt
@@ -15,7 +15,7 @@
             │   ├── rest: ∅
             │   ├── posts: (length: 0)
             │   ├── keywords: (length: 1)
-            │   │   └── @ KeywordParameterNode (location: (1,11)-(1,15))
+            │   │   └── @ OptionalKeywordParameterNode (location: (1,11)-(1,15))
             │   │       ├── name: :b
             │   │       ├── name_loc: (1,11)-(1,13) = "b:"
             │   │       └── value:
diff --git a/test/prism/snapshots/seattlerb/f_kw.txt b/test/prism/snapshots/seattlerb/f_kw.txt
index cbc29b9c..435f5547 100644
--- a/test/prism/snapshots/seattlerb/f_kw.txt
+++ b/test/prism/snapshots/seattlerb/f_kw.txt
@@ -14,7 +14,7 @@
             │   ├── rest: ∅
             │   ├── posts: (length: 0)
             │   ├── keywords: (length: 1)
-            │   │   └── @ KeywordParameterNode (location: (1,6)-(1,10))
+            │   │   └── @ OptionalKeywordParameterNode (location: (1,6)-(1,10))
             │   │       ├── name: :k
             │   │       ├── name_loc: (1,6)-(1,8) = "k:"
             │   │       └── value:
diff --git a/test/prism/snapshots/seattlerb/f_kw__required.txt b/test/prism/snapshots/seattlerb/f_kw__required.txt
index 16d94d6b..62a17289 100644
--- a/test/prism/snapshots/seattlerb/f_kw__required.txt
+++ b/test/prism/snapshots/seattlerb/f_kw__required.txt
@@ -14,10 +14,9 @@
             │   ├── rest: ∅
             │   ├── posts: (length: 0)
             │   ├── keywords: (length: 1)
-            │   │   └── @ KeywordParameterNode (location: (1,6)-(1,8))
+            │   │   └── @ RequiredKeywordParameterNode (location: (1,6)-(1,8))
             │   │       ├── name: :k
-            │   │       ├── name_loc: (1,6)-(1,8) = "k:"
-            │   │       └── value: ∅
+            │   │       └── name_loc: (1,6)-(1,8) = "k:"
             │   ├── keyword_rest: ∅
             │   └── block: ∅
             ├── body: ∅
diff --git a/test/prism/snapshots/seattlerb/iter_kwarg.txt b/test/prism/snapshots/seattlerb/iter_kwarg.txt
index b0b02168..e80e6b59 100644
--- a/test/prism/snapshots/seattlerb/iter_kwarg.txt
+++ b/test/prism/snapshots/seattlerb/iter_kwarg.txt
@@ -22,7 +22,7 @@
             │   │   │   ├── rest: ∅
             │   │   │   ├── posts: (length: 0)
             │   │   │   ├── keywords: (length: 1)
-            │   │   │   │   └── @ KeywordParameterNode (location: (1,5)-(1,9))
+            │   │   │   │   └── @ OptionalKeywordParameterNode (location: (1,5)-(1,9))
             │   │   │   │       ├── name: :b
             │   │   │   │       ├── name_loc: (1,5)-(1,7) = "b:"
             │   │   │   │       └── value:
diff --git a/test/prism/snapshots/seattlerb/iter_kwarg_kwsplat.txt b/test/prism/snapshots/seattlerb/iter_kwarg_kwsplat.txt
index d06f4031..bd910e7d 100644
--- a/test/prism/snapshots/seattlerb/iter_kwarg_kwsplat.txt
+++ b/test/prism/snapshots/seattlerb/iter_kwarg_kwsplat.txt
@@ -22,7 +22,7 @@
             │   │   │   ├── rest: ∅
             │   │   │   ├── posts: (length: 0)
             │   │   │   ├── keywords: (length: 1)
-            │   │   │   │   └── @ KeywordParameterNode (location: (1,5)-(1,9))
+            │   │   │   │   └── @ OptionalKeywordParameterNode (location: (1,5)-(1,9))
             │   │   │   │       ├── name: :b
             │   │   │   │       ├── name_loc: (1,5)-(1,7) = "b:"
             │   │   │   │       └── value:
diff --git a/test/prism/snapshots/seattlerb/required_kwarg_no_value.txt b/test/prism/snapshots/seattlerb/required_kwarg_no_value.txt
index ccfdab2a..8c62ac78 100644
--- a/test/prism/snapshots/seattlerb/required_kwarg_no_value.txt
+++ b/test/prism/snapshots/seattlerb/required_kwarg_no_value.txt
@@ -14,14 +14,12 @@
             │   ├── rest: ∅
             │   ├── posts: (length: 0)
             │   ├── keywords: (length: 2)
-            │   │   ├── @ KeywordParameterNode (location: (1,6)-(1,8))
+            │   │   ├── @ RequiredKeywordParameterNode (location: (1,6)-(1,8))
             │   │   │   ├── name: :a
-            │   │   │   ├── name_loc: (1,6)-(1,8) = "a:"
-            │   │   │   └── value: ∅
-            │   │   └── @ KeywordParameterNode (location: (1,10)-(1,12))
+            │   │   │   └── name_loc: (1,6)-(1,8) = "a:"
+            │   │   └── @ RequiredKeywordParameterNode (location: (1,10)-(1,12))
             │   │       ├── name: :b
-            │   │       ├── name_loc: (1,10)-(1,12) = "b:"
-            │   │       └── value: ∅
+            │   │       └── name_loc: (1,10)-(1,12) = "b:"
             │   ├── keyword_rest: ∅
             │   └── block: ∅
             ├── body: ∅
diff --git a/test/prism/snapshots/seattlerb/stabby_block_kw.txt b/test/prism/snapshots/seattlerb/stabby_block_kw.txt
index e3613e4b..fe95390a 100644
--- a/test/prism/snapshots/seattlerb/stabby_block_kw.txt
+++ b/test/prism/snapshots/seattlerb/stabby_block_kw.txt
@@ -17,7 +17,7 @@
             │   │   ├── rest: ∅
             │   │   ├── posts: (length: 0)
             │   │   ├── keywords: (length: 1)
-            │   │   │   └── @ KeywordParameterNode (location: (1,4)-(1,8))
+            │   │   │   └── @ OptionalKeywordParameterNode (location: (1,4)-(1,8))
             │   │   │       ├── name: :k
             │   │   │       ├── name_loc: (1,4)-(1,6) = "k:"
             │   │   │       └── value:
diff --git a/test/prism/snapshots/seattlerb/stabby_block_kw__required.txt b/test/prism/snapshots/seattlerb/stabby_block_kw__required.txt
index 01391000..99a2e705 100644
--- a/test/prism/snapshots/seattlerb/stabby_block_kw__required.txt
+++ b/test/prism/snapshots/seattlerb/stabby_block_kw__required.txt
@@ -17,10 +17,9 @@
             │   │   ├── rest: ∅
             │   │   ├── posts: (length: 0)
             │   │   ├── keywords: (length: 1)
-            │   │   │   └── @ KeywordParameterNode (location: (1,4)-(1,6))
+            │   │   │   └── @ RequiredKeywordParameterNode (location: (1,4)-(1,6))
             │   │   │       ├── name: :k
-            │   │   │       ├── name_loc: (1,4)-(1,6) = "k:"
-            │   │   │       └── value: ∅
+            │   │   │       └── name_loc: (1,4)-(1,6) = "k:"
             │   │   ├── keyword_rest: ∅
             │   │   └── block: ∅
             │   ├── locals: (length: 0)
diff --git a/test/prism/snapshots/unparser/corpus/literal/def.txt b/test/prism/snapshots/unparser/corpus/literal/def.txt
index 0e283e8f..daafd106 100644
--- a/test/prism/snapshots/unparser/corpus/literal/def.txt
+++ b/test/prism/snapshots/unparser/corpus/literal/def.txt
@@ -194,14 +194,12 @@
         │   │   ├── rest: ∅
         │   │   ├── posts: (length: 0)
         │   │   ├── keywords: (length: 2)
-        │   │   │   ├── @ KeywordParameterNode (location: (21,8)-(21,12))
+        │   │   │   ├── @ RequiredKeywordParameterNode (location: (21,8)-(21,12))
         │   │   │   │   ├── name: :bar
-        │   │   │   │   ├── name_loc: (21,8)-(21,12) = "bar:"
-        │   │   │   │   └── value: ∅
-        │   │   │   └── @ KeywordParameterNode (location: (21,14)-(21,18))
+        │   │   │   │   └── name_loc: (21,8)-(21,12) = "bar:"
+        │   │   │   └── @ RequiredKeywordParameterNode (location: (21,14)-(21,18))
         │   │   │       ├── name: :baz
-        │   │   │       ├── name_loc: (21,14)-(21,18) = "baz:"
-        │   │   │       └── value: ∅
+        │   │   │       └── name_loc: (21,14)-(21,18) = "baz:"
         │   │   ├── keyword_rest: ∅
         │   │   └── block: ∅
         │   ├── body: ∅
@@ -629,7 +627,7 @@
         │   │   ├── rest: ∅
         │   │   ├── posts: (length: 0)
         │   │   ├── keywords: (length: 1)
-        │   │   │   └── @ KeywordParameterNode (location: (74,8)-(74,14))
+        │   │   │   └── @ OptionalKeywordParameterNode (location: (74,8)-(74,14))
         │   │   │       ├── name: :bar
         │   │   │       ├── name_loc: (74,8)-(74,12) = "bar:"
         │   │   │       └── value:
@@ -656,7 +654,7 @@
         │   │   ├── rest: ∅
         │   │   ├── posts: (length: 0)
         │   │   ├── keywords: (length: 1)
-        │   │   │   └── @ KeywordParameterNode (location: (77,8)-(77,16))
+        │   │   │   └── @ OptionalKeywordParameterNode (location: (77,8)-(77,16))
         │   │   │       ├── name: :bar
         │   │   │       ├── name_loc: (77,8)-(77,12) = "bar:"
         │   │   │       └── value:
@@ -691,7 +689,7 @@
         │   │   ├── rest: ∅
         │   │   ├── posts: (length: 0)
         │   │   ├── keywords: (length: 1)
-        │   │   │   └── @ KeywordParameterNode (location: (80,8)-(80,18))
+        │   │   │   └── @ OptionalKeywordParameterNode (location: (80,8)-(80,18))
         │   │   │       ├── name: :bar
         │   │   │       ├── name_loc: (80,8)-(80,12) = "bar:"
         │   │   │       └── value:
@@ -1092,11 +1090,10 @@
         │   │   ├── rest: ∅
         │   │   ├── posts: (length: 0)
         │   │   ├── keywords: (length: 2)
-        │   │   │   ├── @ KeywordParameterNode (location: (123,8)-(123,12))
+        │   │   │   ├── @ RequiredKeywordParameterNode (location: (123,8)-(123,12))
         │   │   │   │   ├── name: :bar
-        │   │   │   │   ├── name_loc: (123,8)-(123,12) = "bar:"
-        │   │   │   │   └── value: ∅
-        │   │   │   └── @ KeywordParameterNode (location: (123,14)-(123,26))
+        │   │   │   │   └── name_loc: (123,8)-(123,12) = "bar:"
+        │   │   │   └── @ OptionalKeywordParameterNode (location: (123,14)-(123,26))
         │   │   │       ├── name: :baz
         │   │   │       ├── name_loc: (123,14)-(123,18) = "baz:"
         │   │   │       └── value:
diff --git a/test/prism/snapshots/whitequark/args.txt b/test/prism/snapshots/whitequark/args.txt
index 1568396d..5c593ddc 100644
--- a/test/prism/snapshots/whitequark/args.txt
+++ b/test/prism/snapshots/whitequark/args.txt
@@ -369,7 +369,7 @@
         │   │   ├── rest: ∅
         │   │   ├── posts: (length: 0)
         │   │   ├── keywords: (length: 1)
-        │   │   │   └── @ KeywordParameterNode (location: (23,7)-(23,13))
+        │   │   │   └── @ OptionalKeywordParameterNode (location: (23,7)-(23,13))
         │   │   │       ├── name: :foo
         │   │   │       ├── name_loc: (23,7)-(23,11) = "foo:"
         │   │   │       └── value:
@@ -400,13 +400,13 @@
         │   │   ├── rest: ∅
         │   │   ├── posts: (length: 0)
         │   │   ├── keywords: (length: 2)
-        │   │   │   ├── @ KeywordParameterNode (location: (25,7)-(25,13))
+        │   │   │   ├── @ OptionalKeywordParameterNode (location: (25,7)-(25,13))
         │   │   │   │   ├── name: :foo
         │   │   │   │   ├── name_loc: (25,7)-(25,11) = "foo:"
         │   │   │   │   └── value:
         │   │   │   │       @ IntegerNode (location: (25,12)-(25,13))
         │   │   │   │       └── flags: decimal
-        │   │   │   └── @ KeywordParameterNode (location: (25,15)-(25,21))
+        │   │   │   └── @ OptionalKeywordParameterNode (location: (25,15)-(25,21))
         │   │   │       ├── name: :bar
         │   │   │       ├── name_loc: (25,15)-(25,19) = "bar:"
         │   │   │       └── value:
@@ -811,10 +811,9 @@
         │   │   ├── rest: ∅
         │   │   ├── posts: (length: 0)
         │   │   ├── keywords: (length: 1)
-        │   │   │   └── @ KeywordParameterNode (location: (51,6)-(51,10))
+        │   │   │   └── @ RequiredKeywordParameterNode (location: (51,6)-(51,10))
         │   │   │       ├── name: :foo
-        │   │   │       ├── name_loc: (51,6)-(51,10) = "foo:"
-        │   │   │       └── value: ∅
+        │   │   │       └── name_loc: (51,6)-(51,10) = "foo:"
         │   │   ├── keyword_rest: ∅
         │   │   └── block: ∅
         │   ├── body: ∅
@@ -836,7 +835,7 @@
         │   │   ├── rest: ∅
         │   │   ├── posts: (length: 0)
         │   │   ├── keywords: (length: 1)
-        │   │   │   └── @ KeywordParameterNode (location: (54,6)-(54,13))
+        │   │   │   └── @ OptionalKeywordParameterNode (location: (54,6)-(54,13))
         │   │   │       ├── name: :foo
         │   │   │       ├── name_loc: (54,6)-(54,10) = "foo:"
         │   │   │       └── value:
diff --git a/test/prism/snapshots/whitequark/blockargs.txt b/test/prism/snapshots/whitequark/blockargs.txt
index 39ef3adf..ec029681 100644
--- a/test/prism/snapshots/whitequark/blockargs.txt
+++ b/test/prism/snapshots/whitequark/blockargs.txt
@@ -963,7 +963,7 @@
         │   │   │   │   ├── rest: ∅
         │   │   │   │   ├── posts: (length: 0)
         │   │   │   │   ├── keywords: (length: 1)
-        │   │   │   │   │   └── @ KeywordParameterNode (location: (57,4)-(57,10))
+        │   │   │   │   │   └── @ OptionalKeywordParameterNode (location: (57,4)-(57,10))
         │   │   │   │   │       ├── name: :foo
         │   │   │   │   │       ├── name_loc: (57,4)-(57,8) = "foo:"
         │   │   │   │   │       └── value:
@@ -1002,13 +1002,13 @@
         │   │   │   │   ├── rest: ∅
         │   │   │   │   ├── posts: (length: 0)
         │   │   │   │   ├── keywords: (length: 2)
-        │   │   │   │   │   ├── @ KeywordParameterNode (location: (59,4)-(59,10))
+        │   │   │   │   │   ├── @ OptionalKeywordParameterNode (location: (59,4)-(59,10))
         │   │   │   │   │   │   ├── name: :foo
         │   │   │   │   │   │   ├── name_loc: (59,4)-(59,8) = "foo:"
         │   │   │   │   │   │   └── value:
         │   │   │   │   │   │       @ IntegerNode (location: (59,9)-(59,10))
         │   │   │   │   │   │       └── flags: decimal
-        │   │   │   │   │   └── @ KeywordParameterNode (location: (59,12)-(59,18))
+        │   │   │   │   │   └── @ OptionalKeywordParameterNode (location: (59,12)-(59,18))
         │   │   │   │   │       ├── name: :bar
         │   │   │   │   │       ├── name_loc: (59,12)-(59,16) = "bar:"
         │   │   │   │   │       └── value:
@@ -1051,10 +1051,9 @@
         │   │   │   │   ├── rest: ∅
         │   │   │   │   ├── posts: (length: 0)
         │   │   │   │   ├── keywords: (length: 1)
-        │   │   │   │   │   └── @ KeywordParameterNode (location: (61,4)-(61,8))
+        │   │   │   │   │   └── @ RequiredKeywordParameterNode (location: (61,4)-(61,8))
         │   │   │   │   │       ├── name: :foo
-        │   │   │   │   │       ├── name_loc: (61,4)-(61,8) = "foo:"
-        │   │   │   │   │       └── value: ∅
+        │   │   │   │   │       └── name_loc: (61,4)-(61,8) = "foo:"
         │   │   │   │   ├── keyword_rest: ∅
         │   │   │   │   └── block: ∅
         │   │   │   ├── locals: (length: 0)
diff --git a/test/prism/snapshots/whitequark/kwarg.txt b/test/prism/snapshots/whitequark/kwarg.txt
index 72ac3865..7aef902f 100644
--- a/test/prism/snapshots/whitequark/kwarg.txt
+++ b/test/prism/snapshots/whitequark/kwarg.txt
@@ -14,10 +14,9 @@
             │   ├── rest: ∅
             │   ├── posts: (length: 0)
             │   ├── keywords: (length: 1)
-            │   │   └── @ KeywordParameterNode (location: (1,6)-(1,10))
+            │   │   └── @ RequiredKeywordParameterNode (location: (1,6)-(1,10))
             │   │       ├── name: :foo
-            │   │       ├── name_loc: (1,6)-(1,10) = "foo:"
-            │   │       └── value: ∅
+            │   │       └── name_loc: (1,6)-(1,10) = "foo:"
             │   ├── keyword_rest: ∅
             │   └── block: ∅
             ├── body: ∅
diff --git a/test/prism/snapshots/whitequark/kwoptarg.txt b/test/prism/snapshots/whitequark/kwoptarg.txt
index 2a3d2e89..40f6d7e4 100644
--- a/test/prism/snapshots/whitequark/kwoptarg.txt
+++ b/test/prism/snapshots/whitequark/kwoptarg.txt
@@ -14,7 +14,7 @@
             │   ├── rest: ∅
             │   ├── posts: (length: 0)
             │   ├── keywords: (length: 1)
-            │   │   └── @ KeywordParameterNode (location: (1,6)-(1,12))
+            │   │   └── @ OptionalKeywordParameterNode (location: (1,6)-(1,12))
             │   │       ├── name: :foo
             │   │       ├── name_loc: (1,6)-(1,10) = "foo:"
             │   │       └── value:
diff --git a/test/prism/snapshots/whitequark/kwoptarg_with_kwrestarg_and_forwarded_args.txt b/test/prism/snapshots/whitequark/kwoptarg_with_kwrestarg_and_forwarded_args.txt
index 930ee91c..675c6f93 100644
--- a/test/prism/snapshots/whitequark/kwoptarg_with_kwrestarg_and_forwarded_args.txt
+++ b/test/prism/snapshots/whitequark/kwoptarg_with_kwrestarg_and_forwarded_args.txt
@@ -14,7 +14,7 @@
             │   ├── rest: ∅
             │   ├── posts: (length: 0)
             │   ├── keywords: (length: 1)
-            │   │   └── @ KeywordParameterNode (location: (1,6)-(1,12))
+            │   │   └── @ OptionalKeywordParameterNode (location: (1,6)-(1,12))
             │   │       ├── name: :a
             │   │       ├── name_loc: (1,6)-(1,8) = "a:"
             │   │       └── value:
diff --git a/test/prism/snapshots/whitequark/ruby_bug_15789.txt b/test/prism/snapshots/whitequark/ruby_bug_15789.txt
index 93ef6b33..657eb764 100644
--- a/test/prism/snapshots/whitequark/ruby_bug_15789.txt
+++ b/test/prism/snapshots/whitequark/ruby_bug_15789.txt
@@ -80,7 +80,7 @@
             │   │       │   │   ├── rest: ∅
             │   │       │   │   ├── posts: (length: 0)
             │   │       │   │   ├── keywords: (length: 1)
-            │   │       │   │   │   └── @ KeywordParameterNode (location: (3,5)-(3,14))
+            │   │       │   │   │   └── @ OptionalKeywordParameterNode (location: (3,5)-(3,14))
             │   │       │   │   │       ├── name: :a
             │   │       │   │   │       ├── name_loc: (3,5)-(3,7) = "a:"
             │   │       │   │   │       └── value:
diff --git a/test/prism/snapshots/whitequark/ruby_bug_9669.txt b/test/prism/snapshots/whitequark/ruby_bug_9669.txt
index 62a25ef2..1ba582a1 100644
--- a/test/prism/snapshots/whitequark/ruby_bug_9669.txt
+++ b/test/prism/snapshots/whitequark/ruby_bug_9669.txt
@@ -14,10 +14,9 @@
         │   │   ├── rest: ∅
         │   │   ├── posts: (length: 0)
         │   │   ├── keywords: (length: 1)
-        │   │   │   └── @ KeywordParameterNode (location: (1,6)-(1,8))
+        │   │   │   └── @ RequiredKeywordParameterNode (location: (1,6)-(1,8))
         │   │   │       ├── name: :b
-        │   │   │       ├── name_loc: (1,6)-(1,8) = "b:"
-        │   │   │       └── value: ∅
+        │   │   │       └── name_loc: (1,6)-(1,8) = "b:"
         │   │   ├── keyword_rest: ∅
         │   │   └── block: ∅
         │   ├── body:
diff --git a/test/prism/snapshots/whitequark/send_lambda_args_noparen.txt b/test/prism/snapshots/whitequark/send_lambda_args_noparen.txt
index f28ed889..913c9a9b 100644
--- a/test/prism/snapshots/whitequark/send_lambda_args_noparen.txt
+++ b/test/prism/snapshots/whitequark/send_lambda_args_noparen.txt
@@ -17,7 +17,7 @@
         │   │   │   ├── rest: ∅
         │   │   │   ├── posts: (length: 0)
         │   │   │   ├── keywords: (length: 1)
-        │   │   │   │   └── @ KeywordParameterNode (location: (1,3)-(1,7))
+        │   │   │   │   └── @ OptionalKeywordParameterNode (location: (1,3)-(1,7))
         │   │   │   │       ├── name: :a
         │   │   │   │       ├── name_loc: (1,3)-(1,5) = "a:"
         │   │   │   │       └── value:
@@ -43,10 +43,9 @@
             │   │   ├── rest: ∅
             │   │   ├── posts: (length: 0)
             │   │   ├── keywords: (length: 1)
-            │   │   │   └── @ KeywordParameterNode (location: (3,3)-(3,5))
+            │   │   │   └── @ RequiredKeywordParameterNode (location: (3,3)-(3,5))
             │   │   │       ├── name: :a
-            │   │   │       ├── name_loc: (3,3)-(3,5) = "a:"
-            │   │   │       └── value: ∅
+            │   │   │       └── name_loc: (3,3)-(3,5) = "a:"
             │   │   ├── keyword_rest: ∅
             │   │   └── block: ∅
             │   ├── locals: (length: 0)