Browse Source

Start using typed parse node ids in the check stage (#3547)

Goal is to increase type safety, though more work needs to be done (see
added TODOs).

Note that, after this change, check handlers corresponding to deleted
parse node kinds will no longer compile.

---------

Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
josh11b 2 years ago
parent
commit
48c986f52d

+ 1 - 2
toolchain/check/check.cpp

@@ -155,10 +155,9 @@ static auto ProcessParseNodes(Context& context,
     // clang warns on unhandled enum values; clang-tidy is incorrect here.
     // clang warns on unhandled enum values; clang-tidy is incorrect here.
     // NOLINTNEXTLINE(bugprone-switch-missing-default-case)
     // NOLINTNEXTLINE(bugprone-switch-missing-default-case)
     switch (auto parse_kind = context.parse_tree().node_kind(parse_node)) {
     switch (auto parse_kind = context.parse_tree().node_kind(parse_node)) {
-      // TODO: Switch to `Parse::Name##Id(parse_node)` here.
 #define CARBON_PARSE_NODE_KIND(Name)                                         \
 #define CARBON_PARSE_NODE_KIND(Name)                                         \
   case Parse::NodeKind::Name: {                                              \
   case Parse::NodeKind::Name: {                                              \
-    if (!Check::Handle##Name(context, parse_node)) {                         \
+    if (!Check::Handle##Name(context, Parse::Name##Id(parse_node))) {        \
       CARBON_CHECK(err_tracker.seen_error())                                 \
       CARBON_CHECK(err_tracker.seen_error())                                 \
           << "Handle" #Name " returned false without printing a diagnostic"; \
           << "Handle" #Name " returned false without printing a diagnostic"; \
       return false;                                                          \
       return false;                                                          \

+ 1 - 1
toolchain/check/context.h

@@ -534,7 +534,7 @@ class Context {
 
 
 // Parse node handlers. Returns false for unrecoverable errors.
 // Parse node handlers. Returns false for unrecoverable errors.
 #define CARBON_PARSE_NODE_KIND(Name) \
 #define CARBON_PARSE_NODE_KIND(Name) \
-  auto Handle##Name(Context& context, Parse::NodeId parse_node) -> bool;
+  auto Handle##Name(Context& context, Parse::Name##Id parse_node) -> bool;
 #include "toolchain/parse/node_kind.def"
 #include "toolchain/parse/node_kind.def"
 
 
 }  // namespace Carbon::Check
 }  // namespace Carbon::Check

+ 5 - 4
toolchain/check/handle_array.cpp

@@ -9,17 +9,18 @@
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
-auto HandleArrayExprStart(Context& /*context*/, Parse::NodeId /*parse_node*/)
-    -> bool {
+auto HandleArrayExprStart(Context& /*context*/,
+                          Parse::ArrayExprStartId /*parse_node*/) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleArrayExprSemi(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleArrayExprSemi(Context& context, Parse::ArrayExprSemiId parse_node)
+    -> bool {
   context.node_stack().Push(parse_node);
   context.node_stack().Push(parse_node);
   return true;
   return true;
 }
 }
 
 
-auto HandleArrayExpr(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleArrayExpr(Context& context, Parse::ArrayExprId parse_node) -> bool {
   // TODO: Handle array type with undefined bound.
   // TODO: Handle array type with undefined bound.
   if (context.node_stack()
   if (context.node_stack()
           .PopAndDiscardSoloParseNodeIf<Parse::NodeKind::ArrayExprSemi>()) {
           .PopAndDiscardSoloParseNodeIf<Parse::NodeKind::ArrayExprSemi>()) {

+ 6 - 4
toolchain/check/handle_binding_pattern.cpp

@@ -9,7 +9,7 @@
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
-auto HandleAddress(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleAddress(Context& context, Parse::AddressId parse_node) -> bool {
   auto self_param_id =
   auto self_param_id =
       context.node_stack().Pop<Parse::NodeKind::BindingPattern>();
       context.node_stack().Pop<Parse::NodeKind::BindingPattern>();
   auto self_param = context.insts().TryGetAs<SemIR::BindName>(self_param_id);
   auto self_param = context.insts().TryGetAs<SemIR::BindName>(self_param_id);
@@ -28,12 +28,14 @@ auto HandleAddress(Context& context, Parse::NodeId parse_node) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleGenericBindingPattern(Context& context, Parse::NodeId parse_node)
+auto HandleGenericBindingPattern(Context& context,
+                                 Parse::GenericBindingPatternId parse_node)
     -> bool {
     -> bool {
   return context.TODO(parse_node, "GenericBindingPattern");
   return context.TODO(parse_node, "GenericBindingPattern");
 }
 }
 
 
-auto HandleBindingPattern(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleBindingPattern(Context& context, Parse::BindingPatternId parse_node)
+    -> bool {
   auto [type_node, parsed_type_id] =
   auto [type_node, parsed_type_id] =
       context.node_stack().PopExprWithParseNode();
       context.node_stack().PopExprWithParseNode();
   auto type_node_copy = type_node;
   auto type_node_copy = type_node;
@@ -158,7 +160,7 @@ auto HandleBindingPattern(Context& context, Parse::NodeId parse_node) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleTemplate(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleTemplate(Context& context, Parse::TemplateId parse_node) -> bool {
   // TODO: diagnose if this occurs in a `var` context.
   // TODO: diagnose if this occurs in a `var` context.
   return context.TODO(parse_node, "HandleTemplate");
   return context.TODO(parse_node, "HandleTemplate");
 }
 }

+ 5 - 4
toolchain/check/handle_call_expr.cpp

@@ -9,7 +9,7 @@
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
-auto HandleCallExpr(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleCallExpr(Context& context, Parse::CallExprId parse_node) -> bool {
   // Process the final explicit call argument now, but leave the arguments
   // Process the final explicit call argument now, but leave the arguments
   // block on the stack until the end of this function.
   // block on the stack until the end of this function.
   context.ParamOrArgEndNoPop(Parse::NodeKind::CallExprStart);
   context.ParamOrArgEndNoPop(Parse::NodeKind::CallExprStart);
@@ -83,13 +83,14 @@ auto HandleCallExpr(Context& context, Parse::NodeId parse_node) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleCallExprComma(Context& context, Parse::NodeId /*parse_node*/)
-    -> bool {
+auto HandleCallExprComma(Context& context,
+                         Parse::CallExprCommaId /*parse_node*/) -> bool {
   context.ParamOrArgComma();
   context.ParamOrArgComma();
   return true;
   return true;
 }
 }
 
 
-auto HandleCallExprStart(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleCallExprStart(Context& context, Parse::CallExprStartId parse_node)
+    -> bool {
   auto name_id = context.node_stack().PopExpr();
   auto name_id = context.node_stack().PopExpr();
   context.node_stack().Push(parse_node, name_id);
   context.node_stack().Push(parse_node, name_id);
   context.ParamOrArgStart();
   context.ParamOrArgStart();

+ 11 - 8
toolchain/check/handle_class.cpp

@@ -8,7 +8,8 @@
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
-auto HandleClassIntroducer(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleClassIntroducer(Context& context,
+                           Parse::ClassIntroducerId parse_node) -> bool {
   // Create an instruction block to hold the instructions created as part of the
   // Create an instruction block to hold the instructions created as part of the
   // class signature, such as generic parameters.
   // class signature, such as generic parameters.
   context.inst_block_stack().Push();
   context.inst_block_stack().Push();
@@ -111,13 +112,14 @@ static auto BuildClassDecl(Context& context, Parse::NodeId parse_node)
   return {class_decl.class_id, class_decl_id};
   return {class_decl.class_id, class_decl_id};
 }
 }
 
 
-auto HandleClassDecl(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleClassDecl(Context& context, Parse::ClassDeclId parse_node) -> bool {
   BuildClassDecl(context, parse_node);
   BuildClassDecl(context, parse_node);
   context.decl_name_stack().PopScope();
   context.decl_name_stack().PopScope();
   return true;
   return true;
 }
 }
 
 
-auto HandleClassDefinitionStart(Context& context, Parse::NodeId parse_node)
+auto HandleClassDefinitionStart(Context& context,
+                                Parse::ClassDefinitionStartId parse_node)
     -> bool {
     -> bool {
   auto [class_id, class_decl_id] = BuildClassDecl(context, parse_node);
   auto [class_id, class_decl_id] = BuildClassDecl(context, parse_node);
   auto& class_info = context.classes().Get(class_id);
   auto& class_info = context.classes().Get(class_id);
@@ -163,13 +165,13 @@ auto HandleClassDefinitionStart(Context& context, Parse::NodeId parse_node)
   return true;
   return true;
 }
 }
 
 
-auto HandleBaseIntroducer(Context& context, Parse::NodeId /*parse_node*/)
-    -> bool {
+auto HandleBaseIntroducer(Context& context,
+                          Parse::BaseIntroducerId /*parse_node*/) -> bool {
   context.decl_state_stack().Push(DeclState::Base);
   context.decl_state_stack().Push(DeclState::Base);
   return true;
   return true;
 }
 }
 
 
-auto HandleBaseColon(Context& /*context*/, Parse::NodeId /*parse_node*/)
+auto HandleBaseColon(Context& /*context*/, Parse::BaseColonId /*parse_node*/)
     -> bool {
     -> bool {
   return true;
   return true;
 }
 }
@@ -245,7 +247,7 @@ static auto CheckBaseType(Context& context, Parse::NodeId parse_node,
   return {.type_id = base_type_id, .scope_id = base_class_info->scope_id};
   return {.type_id = base_type_id, .scope_id = base_class_info->scope_id};
 }
 }
 
 
-auto HandleBaseDecl(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleBaseDecl(Context& context, Parse::BaseDeclId parse_node) -> bool {
   auto base_type_expr_id = context.node_stack().PopExpr();
   auto base_type_expr_id = context.node_stack().PopExpr();
 
 
   // Process modifiers. `extend` is required, none others are allowed.
   // Process modifiers. `extend` is required, none others are allowed.
@@ -318,7 +320,8 @@ auto HandleBaseDecl(Context& context, Parse::NodeId parse_node) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleClassDefinition(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleClassDefinition(Context& context,
+                           Parse::ClassDefinitionId parse_node) -> bool {
   auto fields_id = context.args_type_info_stack().Pop();
   auto fields_id = context.args_type_info_stack().Pop();
   auto class_id =
   auto class_id =
       context.node_stack().Pop<Parse::NodeKind::ClassDefinitionStart>();
       context.node_stack().Pop<Parse::NodeKind::ClassDefinitionStart>();

+ 6 - 3
toolchain/check/handle_codeblock.cpp

@@ -6,15 +6,18 @@
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
-auto HandleCodeBlockStart(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleCodeBlockStart(Context& context, Parse::CodeBlockStartId parse_node)
+    -> bool {
   context.node_stack().Push(parse_node);
   context.node_stack().Push(parse_node);
   context.PushScope();
   context.PushScope();
   return true;
   return true;
 }
 }
 
 
-auto HandleCodeBlock(Context& context, Parse::NodeId /*parse_node*/) -> bool {
+auto HandleCodeBlock(Context& context, Parse::CodeBlockId /*parse_node*/)
+    -> bool {
   context.PopScope();
   context.PopScope();
-  context.node_stack().PopForSoloParseNode<Parse::NodeKind::CodeBlockStart>();
+  context.node_stack()
+      .PopAndDiscardSoloParseNode<Parse::NodeKind::CodeBlockStart>();
   return true;
   return true;
 }
 }
 
 

+ 2 - 2
toolchain/check/handle_expr_statement.cpp

@@ -21,8 +21,8 @@ static auto HandleDiscardedExpr(Context& context, SemIR::InstId expr_id)
   // TODO: This will eventually need to do some "do not discard" analysis.
   // TODO: This will eventually need to do some "do not discard" analysis.
 }
 }
 
 
-auto HandleExprStatement(Context& context, Parse::NodeId /*parse_node*/)
-    -> bool {
+auto HandleExprStatement(Context& context,
+                         Parse::ExprStatementId /*parse_node*/) -> bool {
   HandleDiscardedExpr(context, context.node_stack().PopExpr());
   HandleDiscardedExpr(context, context.node_stack().PopExpr());
   return true;
   return true;
 }
 }

+ 3 - 2
toolchain/check/handle_file.cpp

@@ -6,7 +6,7 @@
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
-auto HandleFileStart(Context& /*context*/, Parse::NodeId /*parse_node*/)
+auto HandleFileStart(Context& /*context*/, Parse::FileStartId /*parse_node*/)
     -> bool {
     -> bool {
   // No action to perform.
   // No action to perform.
   // TODO: We may want to push `FileStart` as a sentinel so that `Peek`s can't
   // TODO: We may want to push `FileStart` as a sentinel so that `Peek`s can't
@@ -14,7 +14,8 @@ auto HandleFileStart(Context& /*context*/, Parse::NodeId /*parse_node*/)
   return true;
   return true;
 }
 }
 
 
-auto HandleFileEnd(Context& /*context*/, Parse::NodeId /*parse_node*/) -> bool {
+auto HandleFileEnd(Context& /*context*/, Parse::FileEndId /*parse_node*/)
+    -> bool {
   // No action to perform.
   // No action to perform.
   return true;
   return true;
 }
 }

+ 10 - 7
toolchain/check/handle_function.cpp

@@ -174,14 +174,15 @@ static auto BuildFunctionDecl(Context& context, Parse::NodeId parse_node,
   return {function_decl.function_id, function_decl_id};
   return {function_decl.function_id, function_decl_id};
 }
 }
 
 
-auto HandleFunctionDecl(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleFunctionDecl(Context& context, Parse::FunctionDeclId parse_node)
+    -> bool {
   BuildFunctionDecl(context, parse_node, /*is_definition=*/false);
   BuildFunctionDecl(context, parse_node, /*is_definition=*/false);
   context.decl_name_stack().PopScope();
   context.decl_name_stack().PopScope();
   return true;
   return true;
 }
 }
 
 
-auto HandleFunctionDefinition(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleFunctionDefinition(Context& context,
+                              Parse::FunctionDefinitionId parse_node) -> bool {
   SemIR::FunctionId function_id =
   SemIR::FunctionId function_id =
       context.node_stack().Pop<Parse::NodeKind::FunctionDefinitionStart>();
       context.node_stack().Pop<Parse::NodeKind::FunctionDefinitionStart>();
 
 
@@ -205,7 +206,8 @@ auto HandleFunctionDefinition(Context& context, Parse::NodeId parse_node)
   return true;
   return true;
 }
 }
 
 
-auto HandleFunctionDefinitionStart(Context& context, Parse::NodeId parse_node)
+auto HandleFunctionDefinitionStart(Context& context,
+                                   Parse::FunctionDefinitionStartId parse_node)
     -> bool {
     -> bool {
   // Process the declaration portion of the function.
   // Process the declaration portion of the function.
   auto [function_id, decl_id] =
   auto [function_id, decl_id] =
@@ -271,8 +273,8 @@ auto HandleFunctionDefinitionStart(Context& context, Parse::NodeId parse_node)
   return true;
   return true;
 }
 }
 
 
-auto HandleFunctionIntroducer(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleFunctionIntroducer(Context& context,
+                              Parse::FunctionIntroducerId parse_node) -> bool {
   // Create an instruction block to hold the instructions created as part of the
   // Create an instruction block to hold the instructions created as part of the
   // function signature, such as parameter and return types.
   // function signature, such as parameter and return types.
   context.inst_block_stack().Push();
   context.inst_block_stack().Push();
@@ -284,7 +286,8 @@ auto HandleFunctionIntroducer(Context& context, Parse::NodeId parse_node)
   return true;
   return true;
 }
 }
 
 
-auto HandleReturnType(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleReturnType(Context& context, Parse::ReturnTypeId parse_node)
+    -> bool {
   // Propagate the type expression.
   // Propagate the type expression.
   auto [type_parse_node, type_inst_id] =
   auto [type_parse_node, type_inst_id] =
       context.node_stack().PopExprWithParseNode();
       context.node_stack().PopExprWithParseNode();

+ 5 - 3
toolchain/check/handle_if_expr.cpp

@@ -7,7 +7,7 @@
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
-auto HandleIfExprIf(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleIfExprIf(Context& context, Parse::IfExprIfId parse_node) -> bool {
   // Alias parse_node for if/then/else consistency.
   // Alias parse_node for if/then/else consistency.
   auto& if_node = parse_node;
   auto& if_node = parse_node;
 
 
@@ -28,7 +28,8 @@ auto HandleIfExprIf(Context& context, Parse::NodeId parse_node) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleIfExprThen(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleIfExprThen(Context& context, Parse::IfExprThenId parse_node)
+    -> bool {
   auto then_value_id = context.node_stack().PopExpr();
   auto then_value_id = context.node_stack().PopExpr();
   auto else_block_id = context.node_stack().Peek<Parse::NodeKind::IfExprIf>();
   auto else_block_id = context.node_stack().Peek<Parse::NodeKind::IfExprIf>();
 
 
@@ -43,7 +44,8 @@ auto HandleIfExprThen(Context& context, Parse::NodeId parse_node) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleIfExprElse(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleIfExprElse(Context& context, Parse::IfExprElseId parse_node)
+    -> bool {
   // Alias parse_node for if/then/else consistency.
   // Alias parse_node for if/then/else consistency.
   auto& else_node = parse_node;
   auto& else_node = parse_node;
 
 

+ 8 - 5
toolchain/check/handle_if_statement.cpp

@@ -8,12 +8,13 @@
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
-auto HandleIfConditionStart(Context& /*context*/, Parse::NodeId /*parse_node*/)
-    -> bool {
+auto HandleIfConditionStart(Context& /*context*/,
+                            Parse::IfConditionStartId /*parse_node*/) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleIfCondition(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleIfCondition(Context& context, Parse::IfConditionId parse_node)
+    -> bool {
   // Convert the condition to `bool`.
   // Convert the condition to `bool`.
   auto cond_value_id = context.node_stack().PopExpr();
   auto cond_value_id = context.node_stack().PopExpr();
   cond_value_id = ConvertToBoolValue(context, parse_node, cond_value_id);
   cond_value_id = ConvertToBoolValue(context, parse_node, cond_value_id);
@@ -34,7 +35,8 @@ auto HandleIfCondition(Context& context, Parse::NodeId parse_node) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleIfStatementElse(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleIfStatementElse(Context& context,
+                           Parse::IfStatementElseId parse_node) -> bool {
   auto else_block_id = context.node_stack().Pop<Parse::NodeKind::IfCondition>();
   auto else_block_id = context.node_stack().Pop<Parse::NodeKind::IfCondition>();
 
 
   // Switch to emitting the `else` block.
   // Switch to emitting the `else` block.
@@ -45,7 +47,8 @@ auto HandleIfStatementElse(Context& context, Parse::NodeId parse_node) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleIfStatement(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleIfStatement(Context& context, Parse::IfStatementId parse_node)
+    -> bool {
   switch (auto kind = context.node_stack().PeekParseNodeKind()) {
   switch (auto kind = context.node_stack().PeekParseNodeKind()) {
     case Parse::NodeKind::IfCondition: {
     case Parse::NodeKind::IfCondition: {
       // Branch from then block to else block, and start emitting the else
       // Branch from then block to else block, and start emitting the else

+ 10 - 6
toolchain/check/handle_impl.cpp

@@ -6,28 +6,32 @@
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
-auto HandleImplIntroducer(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleImplIntroducer(Context& context, Parse::ImplIntroducerId parse_node)
+    -> bool {
   return context.TODO(parse_node, "HandleImplIntroducer");
   return context.TODO(parse_node, "HandleImplIntroducer");
 }
 }
 
 
-auto HandleImplForall(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleImplForall(Context& context, Parse::ImplForallId parse_node)
+    -> bool {
   return context.TODO(parse_node, "HandleImplForall");
   return context.TODO(parse_node, "HandleImplForall");
 }
 }
 
 
-auto HandleImplAs(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleImplAs(Context& context, Parse::ImplAsId parse_node) -> bool {
   return context.TODO(parse_node, "HandleImplAs");
   return context.TODO(parse_node, "HandleImplAs");
 }
 }
 
 
-auto HandleImplDecl(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleImplDecl(Context& context, Parse::ImplDeclId parse_node) -> bool {
   return context.TODO(parse_node, "HandleImplDecl");
   return context.TODO(parse_node, "HandleImplDecl");
 }
 }
 
 
-auto HandleImplDefinitionStart(Context& context, Parse::NodeId parse_node)
+auto HandleImplDefinitionStart(Context& context,
+                               Parse::ImplDefinitionStartId parse_node)
     -> bool {
     -> bool {
   return context.TODO(parse_node, "HandleImplDefinitionStart");
   return context.TODO(parse_node, "HandleImplDefinitionStart");
 }
 }
 
 
-auto HandleImplDefinition(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleImplDefinition(Context& context, Parse::ImplDefinitionId parse_node)
+    -> bool {
   return context.TODO(parse_node, "HandleImplDefinition");
   return context.TODO(parse_node, "HandleImplDefinition");
 }
 }
 
 

+ 23 - 21
toolchain/check/handle_import_and_package.cpp

@@ -9,63 +9,65 @@ namespace Carbon::Check {
 // `import` and `package` are structured by parsing. As a consequence, no
 // `import` and `package` are structured by parsing. As a consequence, no
 // checking logic is needed here.
 // checking logic is needed here.
 
 
-auto HandleImportIntroducer(Context& /*context*/, Parse::NodeId /*parse_node*/)
-    -> bool {
+auto HandleImportIntroducer(Context& /*context*/,
+                            Parse::ImportIntroducerId /*parse_node*/) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleImportDirective(Context& /*context*/, Parse::NodeId /*parse_node*/)
-    -> bool {
+auto HandleImportDirective(Context& /*context*/,
+                           Parse::ImportDirectiveId /*parse_node*/) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleLibraryIntroducer(Context& /*context*/, Parse::NodeId /*parse_node*/)
+auto HandleLibraryIntroducer(Context& /*context*/,
+                             Parse::LibraryIntroducerId /*parse_node*/)
     -> bool {
     -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleLibraryDirective(Context& /*context*/, Parse::NodeId /*parse_node*/)
-    -> bool {
+auto HandleLibraryDirective(Context& /*context*/,
+                            Parse::LibraryDirectiveId /*parse_node*/) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandlePackageIntroducer(Context& /*context*/, Parse::NodeId /*parse_node*/)
+auto HandlePackageIntroducer(Context& /*context*/,
+                             Parse::PackageIntroducerId /*parse_node*/)
     -> bool {
     -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandlePackageDirective(Context& /*context*/, Parse::NodeId /*parse_node*/)
-    -> bool {
+auto HandlePackageDirective(Context& /*context*/,
+                            Parse::PackageDirectiveId /*parse_node*/) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleLibrarySpecifier(Context& /*context*/, Parse::NodeId /*parse_node*/)
-    -> bool {
+auto HandleLibrarySpecifier(Context& /*context*/,
+                            Parse::LibrarySpecifierId /*parse_node*/) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandlePackageName(Context& /*context*/, Parse::NodeId /*parse_node*/)
-    -> bool {
+auto HandlePackageName(Context& /*context*/,
+                       Parse::PackageNameId /*parse_node*/) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleLibraryName(Context& /*context*/, Parse::NodeId /*parse_node*/)
-    -> bool {
+auto HandleLibraryName(Context& /*context*/,
+                       Parse::LibraryNameId /*parse_node*/) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleDefaultLibrary(Context& /*context*/, Parse::NodeId /*parse_node*/)
-    -> bool {
+auto HandleDefaultLibrary(Context& /*context*/,
+                          Parse::DefaultLibraryId /*parse_node*/) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandlePackageApi(Context& /*context*/, Parse::NodeId /*parse_node*/)
+auto HandlePackageApi(Context& /*context*/, Parse::PackageApiId /*parse_node*/)
     -> bool {
     -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandlePackageImpl(Context& /*context*/, Parse::NodeId /*parse_node*/)
-    -> bool {
+auto HandlePackageImpl(Context& /*context*/,
+                       Parse::PackageImplId /*parse_node*/) -> bool {
   return true;
   return true;
 }
 }
 
 

+ 3 - 3
toolchain/check/handle_index.cpp

@@ -9,8 +9,8 @@
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
-auto HandleIndexExprStart(Context& /*context*/, Parse::NodeId /*parse_node*/)
-    -> bool {
+auto HandleIndexExprStart(Context& /*context*/,
+                          Parse::IndexExprStartId /*parse_node*/) -> bool {
   // Leave the expression on the stack for IndexExpr.
   // Leave the expression on the stack for IndexExpr.
   return true;
   return true;
 }
 }
@@ -35,7 +35,7 @@ static auto ValidateIntLiteralBound(Context& context, Parse::NodeId parse_node,
   return &index_val;
   return &index_val;
 }
 }
 
 
-auto HandleIndexExpr(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleIndexExpr(Context& context, Parse::IndexExprId parse_node) -> bool {
   auto index_inst_id = context.node_stack().PopExpr();
   auto index_inst_id = context.node_stack().PopExpr();
   auto index_inst = context.insts().Get(index_inst_id);
   auto index_inst = context.insts().Get(index_inst_id);
   auto operand_inst_id = context.node_stack().PopExpr();
   auto operand_inst_id = context.node_stack().PopExpr();

+ 8 - 5
toolchain/check/handle_interface.cpp

@@ -7,7 +7,8 @@
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
-auto HandleInterfaceIntroducer(Context& context, Parse::NodeId parse_node)
+auto HandleInterfaceIntroducer(Context& context,
+                               Parse::InterfaceIntroducerId parse_node)
     -> bool {
     -> bool {
   // Create an instruction block to hold the instructions created as part of the
   // Create an instruction block to hold the instructions created as part of the
   // interface signature, such as generic parameters.
   // interface signature, such as generic parameters.
@@ -83,14 +84,15 @@ static auto BuildInterfaceDecl(Context& context, Parse::NodeId parse_node)
   return {interface_decl.interface_id, interface_decl_id};
   return {interface_decl.interface_id, interface_decl_id};
 }
 }
 
 
-auto HandleInterfaceDecl(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleInterfaceDecl(Context& context, Parse::InterfaceDeclId parse_node)
+    -> bool {
   BuildInterfaceDecl(context, parse_node);
   BuildInterfaceDecl(context, parse_node);
   context.decl_name_stack().PopScope();
   context.decl_name_stack().PopScope();
   return true;
   return true;
 }
 }
 
 
-auto HandleInterfaceDefinitionStart(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleInterfaceDefinitionStart(
+    Context& context, Parse::InterfaceDefinitionStartId parse_node) -> bool {
   auto [interface_id, interface_decl_id] =
   auto [interface_id, interface_decl_id] =
       BuildInterfaceDecl(context, parse_node);
       BuildInterfaceDecl(context, parse_node);
   auto& interface_info = context.interfaces().Get(interface_id);
   auto& interface_info = context.interfaces().Get(interface_id);
@@ -134,7 +136,8 @@ auto HandleInterfaceDefinitionStart(Context& context, Parse::NodeId parse_node)
   return true;
   return true;
 }
 }
 
 
-auto HandleInterfaceDefinition(Context& context, Parse::NodeId /*parse_node*/)
+auto HandleInterfaceDefinition(Context& context,
+                               Parse::InterfaceDefinitionId /*parse_node*/)
     -> bool {
     -> bool {
   auto interface_id =
   auto interface_id =
       context.node_stack().Pop<Parse::NodeKind::InterfaceDefinitionStart>();
       context.node_stack().Pop<Parse::NodeKind::InterfaceDefinitionStart>();

+ 5 - 4
toolchain/check/handle_let.cpp

@@ -9,7 +9,7 @@
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
-auto HandleLetDecl(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleLetDecl(Context& context, Parse::LetDeclId parse_node) -> bool {
   auto value_id = context.node_stack().PopExpr();
   auto value_id = context.node_stack().PopExpr();
   if (context.node_stack().PeekIs<Parse::NodeKind::TuplePattern>()) {
   if (context.node_stack().PeekIs<Parse::NodeKind::TuplePattern>()) {
     return context.TODO(parse_node, "tuple pattern in let");
     return context.TODO(parse_node, "tuple pattern in let");
@@ -56,15 +56,16 @@ auto HandleLetDecl(Context& context, Parse::NodeId parse_node) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleLetIntroducer(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleLetIntroducer(Context& context, Parse::LetIntroducerId parse_node)
+    -> bool {
   context.decl_state_stack().Push(DeclState::Let);
   context.decl_state_stack().Push(DeclState::Let);
   // Push a bracketing node to establish the pattern context.
   // Push a bracketing node to establish the pattern context.
   context.node_stack().Push(parse_node);
   context.node_stack().Push(parse_node);
   return true;
   return true;
 }
 }
 
 
-auto HandleLetInitializer(Context& /*context*/, Parse::NodeId /*parse_node*/)
-    -> bool {
+auto HandleLetInitializer(Context& /*context*/,
+                          Parse::LetInitializerId /*parse_node*/) -> bool {
   return true;
   return true;
 }
 }
 
 

+ 22 - 14
toolchain/check/handle_literal.cpp

@@ -6,8 +6,8 @@
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
-auto HandleBoolLiteralFalse(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleBoolLiteralFalse(Context& context,
+                            Parse::BoolLiteralFalseId parse_node) -> bool {
   context.AddInstAndPush(
   context.AddInstAndPush(
       parse_node,
       parse_node,
       SemIR::BoolLiteral{parse_node,
       SemIR::BoolLiteral{parse_node,
@@ -16,7 +16,8 @@ auto HandleBoolLiteralFalse(Context& context, Parse::NodeId parse_node)
   return true;
   return true;
 }
 }
 
 
-auto HandleBoolLiteralTrue(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleBoolLiteralTrue(Context& context,
+                           Parse::BoolLiteralTrueId parse_node) -> bool {
   context.AddInstAndPush(
   context.AddInstAndPush(
       parse_node,
       parse_node,
       SemIR::BoolLiteral{parse_node,
       SemIR::BoolLiteral{parse_node,
@@ -25,7 +26,8 @@ auto HandleBoolLiteralTrue(Context& context, Parse::NodeId parse_node) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleIntLiteral(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleIntLiteral(Context& context, Parse::IntLiteralId parse_node)
+    -> bool {
   context.AddInstAndPush(
   context.AddInstAndPush(
       parse_node,
       parse_node,
       SemIR::IntLiteral{parse_node,
       SemIR::IntLiteral{parse_node,
@@ -35,7 +37,8 @@ auto HandleIntLiteral(Context& context, Parse::NodeId parse_node) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleRealLiteral(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleRealLiteral(Context& context, Parse::RealLiteralId parse_node)
+    -> bool {
   context.AddInstAndPush(
   context.AddInstAndPush(
       parse_node,
       parse_node,
       SemIR::RealLiteral{parse_node,
       SemIR::RealLiteral{parse_node,
@@ -45,7 +48,8 @@ auto HandleRealLiteral(Context& context, Parse::NodeId parse_node) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleStringLiteral(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleStringLiteral(Context& context, Parse::StringLiteralId parse_node)
+    -> bool {
   context.AddInstAndPush(
   context.AddInstAndPush(
       parse_node,
       parse_node,
       SemIR::StringLiteral{
       SemIR::StringLiteral{
@@ -55,12 +59,14 @@ auto HandleStringLiteral(Context& context, Parse::NodeId parse_node) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleBoolTypeLiteral(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleBoolTypeLiteral(Context& context,
+                           Parse::BoolTypeLiteralId parse_node) -> bool {
   context.node_stack().Push(parse_node, SemIR::InstId::BuiltinBoolType);
   context.node_stack().Push(parse_node, SemIR::InstId::BuiltinBoolType);
   return true;
   return true;
 }
 }
 
 
-auto HandleIntTypeLiteral(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleIntTypeLiteral(Context& context, Parse::IntTypeLiteralId parse_node)
+    -> bool {
   auto text = context.tokens().GetTokenText(
   auto text = context.tokens().GetTokenText(
       context.parse_tree().node_token(parse_node));
       context.parse_tree().node_token(parse_node));
   if (text != "i32") {
   if (text != "i32") {
@@ -70,13 +76,14 @@ auto HandleIntTypeLiteral(Context& context, Parse::NodeId parse_node) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleUnsignedIntTypeLiteral(Context& context, Parse::NodeId parse_node)
+auto HandleUnsignedIntTypeLiteral(Context& context,
+                                  Parse::UnsignedIntTypeLiteralId parse_node)
     -> bool {
     -> bool {
   return context.TODO(parse_node, "Need to support unsigned type literals");
   return context.TODO(parse_node, "Need to support unsigned type literals");
 }
 }
 
 
-auto HandleFloatTypeLiteral(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleFloatTypeLiteral(Context& context,
+                            Parse::FloatTypeLiteralId parse_node) -> bool {
   auto text = context.tokens().GetTokenText(
   auto text = context.tokens().GetTokenText(
       context.parse_tree().node_token(parse_node));
       context.parse_tree().node_token(parse_node));
   if (text != "f64") {
   if (text != "f64") {
@@ -86,13 +93,14 @@ auto HandleFloatTypeLiteral(Context& context, Parse::NodeId parse_node)
   return true;
   return true;
 }
 }
 
 
-auto HandleStringTypeLiteral(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleStringTypeLiteral(Context& context,
+                             Parse::StringTypeLiteralId parse_node) -> bool {
   context.node_stack().Push(parse_node, SemIR::InstId::BuiltinStringType);
   context.node_stack().Push(parse_node, SemIR::InstId::BuiltinStringType);
   return true;
   return true;
 }
 }
 
 
-auto HandleTypeTypeLiteral(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleTypeTypeLiteral(Context& context,
+                           Parse::TypeTypeLiteralId parse_node) -> bool {
   context.node_stack().Push(parse_node, SemIR::InstId::BuiltinTypeType);
   context.node_stack().Push(parse_node, SemIR::InstId::BuiltinTypeType);
   return true;
   return true;
 }
 }

+ 20 - 12
toolchain/check/handle_loop_statement.cpp

@@ -7,12 +7,13 @@
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
-auto HandleBreakStatement(Context& /*context*/, Parse::NodeId /*parse_node*/)
-    -> bool {
+auto HandleBreakStatement(Context& /*context*/,
+                          Parse::BreakStatementId /*parse_node*/) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleBreakStatementStart(Context& context, Parse::NodeId parse_node)
+auto HandleBreakStatementStart(Context& context,
+                               Parse::BreakStatementStartId parse_node)
     -> bool {
     -> bool {
   auto& stack = context.break_continue_stack();
   auto& stack = context.break_continue_stack();
   if (stack.empty()) {
   if (stack.empty()) {
@@ -28,12 +29,14 @@ auto HandleBreakStatementStart(Context& context, Parse::NodeId parse_node)
   return true;
   return true;
 }
 }
 
 
-auto HandleContinueStatement(Context& /*context*/, Parse::NodeId /*parse_node*/)
+auto HandleContinueStatement(Context& /*context*/,
+                             Parse::ContinueStatementId /*parse_node*/)
     -> bool {
     -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleContinueStatementStart(Context& context, Parse::NodeId parse_node)
+auto HandleContinueStatementStart(Context& context,
+                                  Parse::ContinueStatementStartId parse_node)
     -> bool {
     -> bool {
   auto& stack = context.break_continue_stack();
   auto& stack = context.break_continue_stack();
   if (stack.empty()) {
   if (stack.empty()) {
@@ -49,24 +52,27 @@ auto HandleContinueStatementStart(Context& context, Parse::NodeId parse_node)
   return true;
   return true;
 }
 }
 
 
-auto HandleForHeader(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleForHeader(Context& context, Parse::ForHeaderId parse_node) -> bool {
   return context.TODO(parse_node, "HandleForHeader");
   return context.TODO(parse_node, "HandleForHeader");
 }
 }
 
 
-auto HandleForHeaderStart(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleForHeaderStart(Context& context, Parse::ForHeaderStartId parse_node)
+    -> bool {
   return context.TODO(parse_node, "HandleForHeaderStart");
   return context.TODO(parse_node, "HandleForHeaderStart");
 }
 }
 
 
-auto HandleForIn(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleForIn(Context& context, Parse::ForInId parse_node) -> bool {
   context.decl_state_stack().Pop(DeclState::Var);
   context.decl_state_stack().Pop(DeclState::Var);
   return context.TODO(parse_node, "HandleForIn");
   return context.TODO(parse_node, "HandleForIn");
 }
 }
 
 
-auto HandleForStatement(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleForStatement(Context& context, Parse::ForStatementId parse_node)
+    -> bool {
   return context.TODO(parse_node, "HandleForStatement");
   return context.TODO(parse_node, "HandleForStatement");
 }
 }
 
 
-auto HandleWhileConditionStart(Context& context, Parse::NodeId parse_node)
+auto HandleWhileConditionStart(Context& context,
+                               Parse::WhileConditionStartId parse_node)
     -> bool {
     -> bool {
   // Branch to the loop header block. Note that we create a new block here even
   // Branch to the loop header block. Note that we create a new block here even
   // if the current block is empty; this ensures that the loop always has a
   // if the current block is empty; this ensures that the loop always has a
@@ -82,7 +88,8 @@ auto HandleWhileConditionStart(Context& context, Parse::NodeId parse_node)
   return true;
   return true;
 }
 }
 
 
-auto HandleWhileCondition(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleWhileCondition(Context& context, Parse::WhileConditionId parse_node)
+    -> bool {
   auto cond_value_id = context.node_stack().PopExpr();
   auto cond_value_id = context.node_stack().PopExpr();
   auto loop_header_id =
   auto loop_header_id =
       context.node_stack().Peek<Parse::NodeKind::WhileConditionStart>();
       context.node_stack().Peek<Parse::NodeKind::WhileConditionStart>();
@@ -104,7 +111,8 @@ auto HandleWhileCondition(Context& context, Parse::NodeId parse_node) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleWhileStatement(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleWhileStatement(Context& context, Parse::WhileStatementId parse_node)
+    -> bool {
   auto loop_exit_id =
   auto loop_exit_id =
       context.node_stack().Pop<Parse::NodeKind::WhileCondition>();
       context.node_stack().Pop<Parse::NodeKind::WhileCondition>();
   auto loop_header_id =
   auto loop_header_id =

+ 4 - 4
toolchain/check/handle_modifier.cpp

@@ -62,10 +62,10 @@ static auto HandleModifier(Context& context, Parse::NodeId parse_node,
 }
 }
 
 
 #define CARBON_PARSE_NODE_KIND(...)
 #define CARBON_PARSE_NODE_KIND(...)
-#define CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Name, ...)                  \
-  auto Handle##Name##Modifier(Context& context, Parse::NodeId parse_node) \
-      -> bool {                                                           \
-    return HandleModifier(context, parse_node, KeywordModifierSet::Name); \
+#define CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Name, ...)                    \
+  auto Handle##Name##Modifier(Context& context,                             \
+                              Parse::Name##ModifierId parse_node) -> bool { \
+    return HandleModifier(context, parse_node, KeywordModifierSet::Name);   \
   }
   }
 #include "toolchain/parse/node_kind.def"
 #include "toolchain/parse/node_kind.def"
 
 

+ 19 - 14
toolchain/check/handle_name.cpp

@@ -89,8 +89,8 @@ static auto IsInstanceMethod(const SemIR::File& sem_ir,
   return false;
   return false;
 }
 }
 
 
-auto HandleMemberAccessExpr(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleMemberAccessExpr(Context& context,
+                            Parse::MemberAccessExprId parse_node) -> bool {
   SemIR::NameId name_id = context.node_stack().PopName();
   SemIR::NameId name_id = context.node_stack().PopName();
   auto base_id = context.node_stack().PopExpr();
   auto base_id = context.node_stack().PopExpr();
 
 
@@ -246,7 +246,8 @@ auto HandleMemberAccessExpr(Context& context, Parse::NodeId parse_node)
   return true;
   return true;
 }
 }
 
 
-auto HandlePointerMemberAccessExpr(Context& context, Parse::NodeId parse_node)
+auto HandlePointerMemberAccessExpr(Context& context,
+                                   Parse::PointerMemberAccessExprId parse_node)
     -> bool {
     -> bool {
   return context.TODO(parse_node, "HandlePointerMemberAccessExpr");
   return context.TODO(parse_node, "HandlePointerMemberAccessExpr");
 }
 }
@@ -276,7 +277,8 @@ static auto HandleNameAsExpr(Context& context, Parse::NodeId parse_node,
   return true;
   return true;
 }
 }
 
 
-auto HandleIdentifierName(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleIdentifierName(Context& context, Parse::IdentifierNameId parse_node)
+    -> bool {
   // The parent is responsible for binding the name.
   // The parent is responsible for binding the name.
   auto name_id = GetIdentifierAsName(context, parse_node);
   auto name_id = GetIdentifierAsName(context, parse_node);
   if (!name_id) {
   if (!name_id) {
@@ -286,8 +288,8 @@ auto HandleIdentifierName(Context& context, Parse::NodeId parse_node) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleIdentifierNameExpr(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleIdentifierNameExpr(Context& context,
+                              Parse::IdentifierNameExprId parse_node) -> bool {
   auto name_id = GetIdentifierAsName(context, parse_node);
   auto name_id = GetIdentifierAsName(context, parse_node);
   if (!name_id) {
   if (!name_id) {
     return context.TODO(parse_node, "Error recovery from keyword name.");
     return context.TODO(parse_node, "Error recovery from keyword name.");
@@ -295,27 +297,29 @@ auto HandleIdentifierNameExpr(Context& context, Parse::NodeId parse_node)
   return HandleNameAsExpr(context, parse_node, *name_id);
   return HandleNameAsExpr(context, parse_node, *name_id);
 }
 }
 
 
-auto HandleBaseName(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleBaseName(Context& context, Parse::BaseNameId parse_node) -> bool {
   context.node_stack().Push(parse_node, SemIR::NameId::Base);
   context.node_stack().Push(parse_node, SemIR::NameId::Base);
   return true;
   return true;
 }
 }
 
 
-auto HandleSelfTypeNameExpr(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleSelfTypeNameExpr(Context& context,
+                            Parse::SelfTypeNameExprId parse_node) -> bool {
   return HandleNameAsExpr(context, parse_node, SemIR::NameId::SelfType);
   return HandleNameAsExpr(context, parse_node, SemIR::NameId::SelfType);
 }
 }
 
 
-auto HandleSelfValueName(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleSelfValueName(Context& context, Parse::SelfValueNameId parse_node)
+    -> bool {
   context.node_stack().Push(parse_node, SemIR::NameId::SelfValue);
   context.node_stack().Push(parse_node, SemIR::NameId::SelfValue);
   return true;
   return true;
 }
 }
 
 
-auto HandleSelfValueNameExpr(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleSelfValueNameExpr(Context& context,
+                             Parse::SelfValueNameExprId parse_node) -> bool {
   return HandleNameAsExpr(context, parse_node, SemIR::NameId::SelfValue);
   return HandleNameAsExpr(context, parse_node, SemIR::NameId::SelfValue);
 }
 }
 
 
-auto HandleQualifiedName(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleQualifiedName(Context& context, Parse::QualifiedNameId parse_node)
+    -> bool {
   auto [parse_node2, name_id2] = context.node_stack().PopNameWithParseNode();
   auto [parse_node2, name_id2] = context.node_stack().PopNameWithParseNode();
 
 
   Parse::NodeId parse_node1 = context.node_stack().PeekParseNode();
   Parse::NodeId parse_node1 = context.node_stack().PeekParseNode();
@@ -346,7 +350,8 @@ auto HandleQualifiedName(Context& context, Parse::NodeId parse_node) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandlePackageExpr(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandlePackageExpr(Context& context, Parse::PackageExprId parse_node)
+    -> bool {
   context.AddInstAndPush(
   context.AddInstAndPush(
       parse_node,
       parse_node,
       SemIR::NameRef{
       SemIR::NameRef{

+ 9 - 7
toolchain/check/handle_named_constraint.cpp

@@ -6,23 +6,25 @@
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
-auto HandleNamedConstraintDecl(Context& context, Parse::NodeId parse_node)
+auto HandleNamedConstraintDecl(Context& context,
+                               Parse::NamedConstraintDeclId parse_node)
     -> bool {
     -> bool {
   return context.TODO(parse_node, "HandleNamedConstraintDecl");
   return context.TODO(parse_node, "HandleNamedConstraintDecl");
 }
 }
 
 
-auto HandleNamedConstraintDefinition(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleNamedConstraintDefinition(
+    Context& context, Parse::NamedConstraintDefinitionId parse_node) -> bool {
   return context.TODO(parse_node, "HandleNamedConstraintDefinition");
   return context.TODO(parse_node, "HandleNamedConstraintDefinition");
 }
 }
 
 
-auto HandleNamedConstraintDefinitionStart(Context& context,
-                                          Parse::NodeId parse_node) -> bool {
+auto HandleNamedConstraintDefinitionStart(
+    Context& context, Parse::NamedConstraintDefinitionStartId parse_node)
+    -> bool {
   return context.TODO(parse_node, "HandleNamedConstraintDefinitionStart");
   return context.TODO(parse_node, "HandleNamedConstraintDefinitionStart");
 }
 }
 
 
-auto HandleNamedConstraintIntroducer(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleNamedConstraintIntroducer(
+    Context& context, Parse::NamedConstraintIntroducerId parse_node) -> bool {
   return context.TODO(parse_node, "HandleNamedConstraintIntroducer");
   return context.TODO(parse_node, "HandleNamedConstraintIntroducer");
 }
 }
 
 

+ 3 - 3
toolchain/check/handle_namespace.cpp

@@ -10,15 +10,15 @@
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
-auto HandleNamespaceStart(Context& context, Parse::NodeId /*parse_node*/)
-    -> bool {
+auto HandleNamespaceStart(Context& context,
+                          Parse::NamespaceStartId /*parse_node*/) -> bool {
   // Optional modifiers and the name follow.
   // Optional modifiers and the name follow.
   context.decl_state_stack().Push(DeclState::Namespace);
   context.decl_state_stack().Push(DeclState::Namespace);
   context.decl_name_stack().PushScopeAndStartName();
   context.decl_name_stack().PushScopeAndStartName();
   return true;
   return true;
 }
 }
 
 
-auto HandleNamespace(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleNamespace(Context& context, Parse::NamespaceId parse_node) -> bool {
   auto name_context = context.decl_name_stack().FinishName();
   auto name_context = context.decl_name_stack().FinishName();
   LimitModifiersOnDecl(context, KeywordModifierSet::None,
   LimitModifiersOnDecl(context, KeywordModifierSet::None,
                        Lex::TokenKind::Namespace);
                        Lex::TokenKind::Namespace);

+ 9 - 7
toolchain/check/handle_noop.cpp

@@ -6,28 +6,30 @@
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
-auto HandleEmptyDecl(Context& /*context*/, Parse::NodeId /*parse_node*/)
+auto HandleEmptyDecl(Context& /*context*/, Parse::EmptyDeclId /*parse_node*/)
     -> bool {
     -> bool {
   // Empty declarations have no actions associated.
   // Empty declarations have no actions associated.
   return true;
   return true;
 }
 }
 
 
-auto HandleInvalidParse(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleInvalidParse(Context& context, Parse::InvalidParseId parse_node)
+    -> bool {
   return context.TODO(parse_node, "HandleInvalidParse");
   return context.TODO(parse_node, "HandleInvalidParse");
 }
 }
 
 
-auto HandleInvalidParseStart(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleInvalidParseStart(Context& context,
+                             Parse::InvalidParseStartId parse_node) -> bool {
   return context.TODO(parse_node, "HandleInvalidParseStart");
   return context.TODO(parse_node, "HandleInvalidParseStart");
 }
 }
 
 
-auto HandleInvalidParseSubtree(Context& context, Parse::NodeId parse_node)
+auto HandleInvalidParseSubtree(Context& context,
+                               Parse::InvalidParseSubtreeId parse_node)
     -> bool {
     -> bool {
   return context.TODO(parse_node, "HandleInvalidParseSubtree");
   return context.TODO(parse_node, "HandleInvalidParseSubtree");
 }
 }
 
 
-auto HandlePlaceholder(Context& /*context*/, Parse::NodeId /*parse_node*/)
-    -> bool {
+auto HandlePlaceholder(Context& /*context*/,
+                       Parse::PlaceholderId /*parse_node*/) -> bool {
   CARBON_FATAL()
   CARBON_FATAL()
       << "Placeholder node should always be replaced before parse completes";
       << "Placeholder node should always be replaced before parse completes";
 }
 }

+ 86 - 67
toolchain/check/handle_operator.cpp

@@ -7,17 +7,19 @@
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
-auto HandleInfixOperatorAmp(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleInfixOperatorAmp(Context& context,
+                            Parse::InfixOperatorAmpId parse_node) -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorAmp");
   return context.TODO(parse_node, "HandleInfixOperatorAmp");
 }
 }
 
 
-auto HandleInfixOperatorAmpEqual(Context& context, Parse::NodeId parse_node)
+auto HandleInfixOperatorAmpEqual(Context& context,
+                                 Parse::InfixOperatorAmpEqualId parse_node)
     -> bool {
     -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorAmpEqual");
   return context.TODO(parse_node, "HandleInfixOperatorAmpEqual");
 }
 }
 
 
-auto HandleInfixOperatorAs(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleInfixOperatorAs(Context& context,
+                           Parse::InfixOperatorAsId parse_node) -> bool {
   auto [rhs_node, rhs_id] = context.node_stack().PopExprWithParseNode();
   auto [rhs_node, rhs_id] = context.node_stack().PopExprWithParseNode();
   auto [lhs_node, lhs_id] = context.node_stack().PopExprWithParseNode();
   auto [lhs_node, lhs_id] = context.node_stack().PopExprWithParseNode();
 
 
@@ -28,18 +30,19 @@ auto HandleInfixOperatorAs(Context& context, Parse::NodeId parse_node) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleInfixOperatorCaret(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleInfixOperatorCaret(Context& context,
+                              Parse::InfixOperatorCaretId parse_node) -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorCaret");
   return context.TODO(parse_node, "HandleInfixOperatorCaret");
 }
 }
 
 
-auto HandleInfixOperatorCaretEqual(Context& context, Parse::NodeId parse_node)
+auto HandleInfixOperatorCaretEqual(Context& context,
+                                   Parse::InfixOperatorCaretEqualId parse_node)
     -> bool {
     -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorCaretEqual");
   return context.TODO(parse_node, "HandleInfixOperatorCaretEqual");
 }
 }
 
 
-auto HandleInfixOperatorEqual(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleInfixOperatorEqual(Context& context,
+                              Parse::InfixOperatorEqualId parse_node) -> bool {
   auto [rhs_node, rhs_id] = context.node_stack().PopExprWithParseNode();
   auto [rhs_node, rhs_id] = context.node_stack().PopExprWithParseNode();
   auto [lhs_node, lhs_id] = context.node_stack().PopExprWithParseNode();
   auto [lhs_node, lhs_id] = context.node_stack().PopExprWithParseNode();
 
 
@@ -63,122 +66,135 @@ auto HandleInfixOperatorEqual(Context& context, Parse::NodeId parse_node)
   return true;
   return true;
 }
 }
 
 
-auto HandleInfixOperatorEqualEqual(Context& context, Parse::NodeId parse_node)
+auto HandleInfixOperatorEqualEqual(Context& context,
+                                   Parse::InfixOperatorEqualEqualId parse_node)
     -> bool {
     -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorEqualEqual");
   return context.TODO(parse_node, "HandleInfixOperatorEqualEqual");
 }
 }
 
 
-auto HandleInfixOperatorExclaimEqual(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleInfixOperatorExclaimEqual(
+    Context& context, Parse::InfixOperatorExclaimEqualId parse_node) -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorExclaimEqual");
   return context.TODO(parse_node, "HandleInfixOperatorExclaimEqual");
 }
 }
 
 
-auto HandleInfixOperatorGreater(Context& context, Parse::NodeId parse_node)
+auto HandleInfixOperatorGreater(Context& context,
+                                Parse::InfixOperatorGreaterId parse_node)
     -> bool {
     -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorGreater");
   return context.TODO(parse_node, "HandleInfixOperatorGreater");
 }
 }
 
 
-auto HandleInfixOperatorGreaterEqual(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleInfixOperatorGreaterEqual(
+    Context& context, Parse::InfixOperatorGreaterEqualId parse_node) -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorGreaterEqual");
   return context.TODO(parse_node, "HandleInfixOperatorGreaterEqual");
 }
 }
 
 
-auto HandleInfixOperatorGreaterGreater(Context& context,
-                                       Parse::NodeId parse_node) -> bool {
+auto HandleInfixOperatorGreaterGreater(
+    Context& context, Parse::InfixOperatorGreaterGreaterId parse_node) -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorGreaterGreater");
   return context.TODO(parse_node, "HandleInfixOperatorGreaterGreater");
 }
 }
 
 
-auto HandleInfixOperatorGreaterGreaterEqual(Context& context,
-                                            Parse::NodeId parse_node) -> bool {
+auto HandleInfixOperatorGreaterGreaterEqual(
+    Context& context, Parse::InfixOperatorGreaterGreaterEqualId parse_node)
+    -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorGreaterGreaterEqual");
   return context.TODO(parse_node, "HandleInfixOperatorGreaterGreaterEqual");
 }
 }
 
 
-auto HandleInfixOperatorLess(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleInfixOperatorLess(Context& context,
+                             Parse::InfixOperatorLessId parse_node) -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorLess");
   return context.TODO(parse_node, "HandleInfixOperatorLess");
 }
 }
 
 
-auto HandleInfixOperatorLessEqual(Context& context, Parse::NodeId parse_node)
+auto HandleInfixOperatorLessEqual(Context& context,
+                                  Parse::InfixOperatorLessEqualId parse_node)
     -> bool {
     -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorLessEqual");
   return context.TODO(parse_node, "HandleInfixOperatorLessEqual");
 }
 }
 
 
-auto HandleInfixOperatorLessEqualGreater(Context& context,
-                                         Parse::NodeId parse_node) -> bool {
+auto HandleInfixOperatorLessEqualGreater(
+    Context& context, Parse::InfixOperatorLessEqualGreaterId parse_node)
+    -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorLessEqualGreater");
   return context.TODO(parse_node, "HandleInfixOperatorLessEqualGreater");
 }
 }
 
 
-auto HandleInfixOperatorLessLess(Context& context, Parse::NodeId parse_node)
+auto HandleInfixOperatorLessLess(Context& context,
+                                 Parse::InfixOperatorLessLessId parse_node)
     -> bool {
     -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorLessLess");
   return context.TODO(parse_node, "HandleInfixOperatorLessLess");
 }
 }
 
 
-auto HandleInfixOperatorLessLessEqual(Context& context,
-                                      Parse::NodeId parse_node) -> bool {
+auto HandleInfixOperatorLessLessEqual(
+    Context& context, Parse::InfixOperatorLessLessEqualId parse_node) -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorLessLessEqual");
   return context.TODO(parse_node, "HandleInfixOperatorLessLessEqual");
 }
 }
 
 
-auto HandleInfixOperatorMinus(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleInfixOperatorMinus(Context& context,
+                              Parse::InfixOperatorMinusId parse_node) -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorMinus");
   return context.TODO(parse_node, "HandleInfixOperatorMinus");
 }
 }
 
 
-auto HandleInfixOperatorMinusEqual(Context& context, Parse::NodeId parse_node)
+auto HandleInfixOperatorMinusEqual(Context& context,
+                                   Parse::InfixOperatorMinusEqualId parse_node)
     -> bool {
     -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorMinusEqual");
   return context.TODO(parse_node, "HandleInfixOperatorMinusEqual");
 }
 }
 
 
-auto HandleInfixOperatorPercent(Context& context, Parse::NodeId parse_node)
+auto HandleInfixOperatorPercent(Context& context,
+                                Parse::InfixOperatorPercentId parse_node)
     -> bool {
     -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorPercent");
   return context.TODO(parse_node, "HandleInfixOperatorPercent");
 }
 }
 
 
-auto HandleInfixOperatorPercentEqual(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleInfixOperatorPercentEqual(
+    Context& context, Parse::InfixOperatorPercentEqualId parse_node) -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorPercentEqual");
   return context.TODO(parse_node, "HandleInfixOperatorPercentEqual");
 }
 }
 
 
-auto HandleInfixOperatorPipe(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleInfixOperatorPipe(Context& context,
+                             Parse::InfixOperatorPipeId parse_node) -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorPipe");
   return context.TODO(parse_node, "HandleInfixOperatorPipe");
 }
 }
 
 
-auto HandleInfixOperatorPipeEqual(Context& context, Parse::NodeId parse_node)
+auto HandleInfixOperatorPipeEqual(Context& context,
+                                  Parse::InfixOperatorPipeEqualId parse_node)
     -> bool {
     -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorPipeEqual");
   return context.TODO(parse_node, "HandleInfixOperatorPipeEqual");
 }
 }
 
 
-auto HandleInfixOperatorPlus(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleInfixOperatorPlus(Context& context,
+                             Parse::InfixOperatorPlusId parse_node) -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorPlus");
   return context.TODO(parse_node, "HandleInfixOperatorPlus");
 }
 }
 
 
-auto HandleInfixOperatorPlusEqual(Context& context, Parse::NodeId parse_node)
+auto HandleInfixOperatorPlusEqual(Context& context,
+                                  Parse::InfixOperatorPlusEqualId parse_node)
     -> bool {
     -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorPlusEqual");
   return context.TODO(parse_node, "HandleInfixOperatorPlusEqual");
 }
 }
 
 
-auto HandleInfixOperatorSlash(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleInfixOperatorSlash(Context& context,
+                              Parse::InfixOperatorSlashId parse_node) -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorSlash");
   return context.TODO(parse_node, "HandleInfixOperatorSlash");
 }
 }
 
 
-auto HandleInfixOperatorSlashEqual(Context& context, Parse::NodeId parse_node)
+auto HandleInfixOperatorSlashEqual(Context& context,
+                                   Parse::InfixOperatorSlashEqualId parse_node)
     -> bool {
     -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorSlashEqual");
   return context.TODO(parse_node, "HandleInfixOperatorSlashEqual");
 }
 }
 
 
-auto HandleInfixOperatorStar(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleInfixOperatorStar(Context& context,
+                             Parse::InfixOperatorStarId parse_node) -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorStar");
   return context.TODO(parse_node, "HandleInfixOperatorStar");
 }
 }
 
 
-auto HandleInfixOperatorStarEqual(Context& context, Parse::NodeId parse_node)
+auto HandleInfixOperatorStarEqual(Context& context,
+                                  Parse::InfixOperatorStarEqualId parse_node)
     -> bool {
     -> bool {
   return context.TODO(parse_node, "HandleInfixOperatorStarEqual");
   return context.TODO(parse_node, "HandleInfixOperatorStarEqual");
 }
 }
 
 
-auto HandlePostfixOperatorStar(Context& context, Parse::NodeId parse_node)
+auto HandlePostfixOperatorStar(Context& context,
+                               Parse::PostfixOperatorStarId parse_node)
     -> bool {
     -> bool {
   auto value_id = context.node_stack().PopExpr();
   auto value_id = context.node_stack().PopExpr();
   auto inner_type_id = ExprAsType(context, parse_node, value_id);
   auto inner_type_id = ExprAsType(context, parse_node, value_id);
@@ -188,8 +204,8 @@ auto HandlePostfixOperatorStar(Context& context, Parse::NodeId parse_node)
   return true;
   return true;
 }
 }
 
 
-auto HandlePrefixOperatorAmp(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandlePrefixOperatorAmp(Context& context,
+                             Parse::PrefixOperatorAmpId parse_node) -> bool {
   auto value_id = context.node_stack().PopExpr();
   auto value_id = context.node_stack().PopExpr();
   // Only durable reference expressions can have their address taken.
   // Only durable reference expressions can have their address taken.
   switch (SemIR::GetExprCategory(context.sem_ir(), value_id)) {
   switch (SemIR::GetExprCategory(context.sem_ir(), value_id)) {
@@ -216,12 +232,14 @@ auto HandlePrefixOperatorAmp(Context& context, Parse::NodeId parse_node)
   return true;
   return true;
 }
 }
 
 
-auto HandlePrefixOperatorCaret(Context& context, Parse::NodeId parse_node)
+auto HandlePrefixOperatorCaret(Context& context,
+                               Parse::PrefixOperatorCaretId parse_node)
     -> bool {
     -> bool {
   return context.TODO(parse_node, "HandlePrefixOperatorCaret");
   return context.TODO(parse_node, "HandlePrefixOperatorCaret");
 }
 }
 
 
-auto HandlePrefixOperatorConst(Context& context, Parse::NodeId parse_node)
+auto HandlePrefixOperatorConst(Context& context,
+                               Parse::PrefixOperatorConstId parse_node)
     -> bool {
     -> bool {
   auto value_id = context.node_stack().PopExpr();
   auto value_id = context.node_stack().PopExpr();
 
 
@@ -241,18 +259,19 @@ auto HandlePrefixOperatorConst(Context& context, Parse::NodeId parse_node)
   return true;
   return true;
 }
 }
 
 
-auto HandlePrefixOperatorMinus(Context& context, Parse::NodeId parse_node)
+auto HandlePrefixOperatorMinus(Context& context,
+                               Parse::PrefixOperatorMinusId parse_node)
     -> bool {
     -> bool {
   return context.TODO(parse_node, "HandlePrefixOperatorMinus");
   return context.TODO(parse_node, "HandlePrefixOperatorMinus");
 }
 }
 
 
-auto HandlePrefixOperatorMinusMinus(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandlePrefixOperatorMinusMinus(
+    Context& context, Parse::PrefixOperatorMinusMinusId parse_node) -> bool {
   return context.TODO(parse_node, "HandlePrefixOperatorMinusMinus");
   return context.TODO(parse_node, "HandlePrefixOperatorMinusMinus");
 }
 }
 
 
-auto HandlePrefixOperatorNot(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandlePrefixOperatorNot(Context& context,
+                             Parse::PrefixOperatorNotId parse_node) -> bool {
   auto value_id = context.node_stack().PopExpr();
   auto value_id = context.node_stack().PopExpr();
   value_id = ConvertToBoolValue(context, parse_node, value_id);
   value_id = ConvertToBoolValue(context, parse_node, value_id);
   context.AddInstAndPush(
   context.AddInstAndPush(
@@ -262,18 +281,14 @@ auto HandlePrefixOperatorNot(Context& context, Parse::NodeId parse_node)
   return true;
   return true;
 }
 }
 
 
-auto HandlePrefixOperatorPlus(Context& context, Parse::NodeId parse_node)
-    -> bool {
-  return context.TODO(parse_node, "HandlePrefixOperatorPlus");
-}
-
-auto HandlePrefixOperatorPlusPlus(Context& context, Parse::NodeId parse_node)
+auto HandlePrefixOperatorPlusPlus(Context& context,
+                                  Parse::PrefixOperatorPlusPlusId parse_node)
     -> bool {
     -> bool {
   return context.TODO(parse_node, "HandlePrefixOperatorPlusPlus");
   return context.TODO(parse_node, "HandlePrefixOperatorPlusPlus");
 }
 }
 
 
-auto HandlePrefixOperatorStar(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandlePrefixOperatorStar(Context& context,
+                              Parse::PrefixOperatorStarId parse_node) -> bool {
   auto value_id = context.node_stack().PopExpr();
   auto value_id = context.node_stack().PopExpr();
   value_id = ConvertToValueExpr(context, value_id);
   value_id = ConvertToValueExpr(context, value_id);
   auto type_id =
   auto type_id =
@@ -339,12 +354,14 @@ static auto HandleShortCircuitOperand(Context& context,
   return true;
   return true;
 }
 }
 
 
-auto HandleShortCircuitOperandAnd(Context& context, Parse::NodeId parse_node)
+auto HandleShortCircuitOperandAnd(Context& context,
+                                  Parse::ShortCircuitOperandAndId parse_node)
     -> bool {
     -> bool {
   return HandleShortCircuitOperand(context, parse_node, /*is_or=*/false);
   return HandleShortCircuitOperand(context, parse_node, /*is_or=*/false);
 }
 }
 
 
-auto HandleShortCircuitOperandOr(Context& context, Parse::NodeId parse_node)
+auto HandleShortCircuitOperandOr(Context& context,
+                                 Parse::ShortCircuitOperandOrId parse_node)
     -> bool {
     -> bool {
   return HandleShortCircuitOperand(context, parse_node, /*is_or=*/true);
   return HandleShortCircuitOperand(context, parse_node, /*is_or=*/true);
 }
 }
@@ -375,12 +392,14 @@ static auto HandleShortCircuitOperator(Context& context,
   return true;
   return true;
 }
 }
 
 
-auto HandleShortCircuitOperatorAnd(Context& context, Parse::NodeId parse_node)
+auto HandleShortCircuitOperatorAnd(Context& context,
+                                   Parse::ShortCircuitOperatorAndId parse_node)
     -> bool {
     -> bool {
   return HandleShortCircuitOperator(context, parse_node);
   return HandleShortCircuitOperator(context, parse_node);
 }
 }
 
 
-auto HandleShortCircuitOperatorOr(Context& context, Parse::NodeId parse_node)
+auto HandleShortCircuitOperatorOr(Context& context,
+                                  Parse::ShortCircuitOperatorOrId parse_node)
     -> bool {
     -> bool {
   return HandleShortCircuitOperator(context, parse_node);
   return HandleShortCircuitOperator(context, parse_node);
 }
 }

+ 7 - 4
toolchain/check/handle_paren.cpp

@@ -6,7 +6,7 @@
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
-auto HandleParenExpr(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleParenExpr(Context& context, Parse::ParenExprId parse_node) -> bool {
   auto value_id = context.node_stack().PopExpr();
   auto value_id = context.node_stack().PopExpr();
   // ParamOrArgStart was called for tuple handling; clean up the ParamOrArg
   // ParamOrArgStart was called for tuple handling; clean up the ParamOrArg
   // support for non-tuple cases.
   // support for non-tuple cases.
@@ -17,19 +17,22 @@ auto HandleParenExpr(Context& context, Parse::NodeId parse_node) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleExprOpenParen(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleExprOpenParen(Context& context, Parse::ExprOpenParenId parse_node)
+    -> bool {
   context.node_stack().Push(parse_node);
   context.node_stack().Push(parse_node);
   context.ParamOrArgStart();
   context.ParamOrArgStart();
   return true;
   return true;
 }
 }
 
 
-auto HandleTupleLiteralComma(Context& context, Parse::NodeId /*parse_node*/)
+auto HandleTupleLiteralComma(Context& context,
+                             Parse::TupleLiteralCommaId /*parse_node*/)
     -> bool {
     -> bool {
   context.ParamOrArgComma();
   context.ParamOrArgComma();
   return true;
   return true;
 }
 }
 
 
-auto HandleTupleLiteral(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleTupleLiteral(Context& context, Parse::TupleLiteralId parse_node)
+    -> bool {
   auto refs_id = context.ParamOrArgEnd(Parse::NodeKind::ExprOpenParen);
   auto refs_id = context.ParamOrArgEnd(Parse::NodeKind::ExprOpenParen);
 
 
   context.node_stack()
   context.node_stack()

+ 10 - 8
toolchain/check/handle_pattern_list.cpp

@@ -6,8 +6,8 @@
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
-auto HandleImplicitParamList(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleImplicitParamList(Context& context,
+                             Parse::ImplicitParamListId parse_node) -> bool {
   auto refs_id = context.ParamOrArgEnd(Parse::NodeKind::ImplicitParamListStart);
   auto refs_id = context.ParamOrArgEnd(Parse::NodeKind::ImplicitParamListStart);
   context.node_stack()
   context.node_stack()
       .PopAndDiscardSoloParseNode<Parse::NodeKind::ImplicitParamListStart>();
       .PopAndDiscardSoloParseNode<Parse::NodeKind::ImplicitParamListStart>();
@@ -17,7 +17,8 @@ auto HandleImplicitParamList(Context& context, Parse::NodeId parse_node)
   return true;
   return true;
 }
 }
 
 
-auto HandleImplicitParamListStart(Context& context, Parse::NodeId parse_node)
+auto HandleImplicitParamListStart(Context& context,
+                                  Parse::ImplicitParamListStartId parse_node)
     -> bool {
     -> bool {
   context.PushScope();
   context.PushScope();
   context.node_stack().Push(parse_node);
   context.node_stack().Push(parse_node);
@@ -25,7 +26,8 @@ auto HandleImplicitParamListStart(Context& context, Parse::NodeId parse_node)
   return true;
   return true;
 }
 }
 
 
-auto HandleTuplePattern(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleTuplePattern(Context& context, Parse::TuplePatternId parse_node)
+    -> bool {
   auto refs_id = context.ParamOrArgEnd(Parse::NodeKind::TuplePatternStart);
   auto refs_id = context.ParamOrArgEnd(Parse::NodeKind::TuplePatternStart);
   context.PopScope();
   context.PopScope();
   context.node_stack()
   context.node_stack()
@@ -34,14 +36,14 @@ auto HandleTuplePattern(Context& context, Parse::NodeId parse_node) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandlePatternListComma(Context& context, Parse::NodeId /*parse_node*/)
-    -> bool {
+auto HandlePatternListComma(Context& context,
+                            Parse::PatternListCommaId /*parse_node*/) -> bool {
   context.ParamOrArgComma();
   context.ParamOrArgComma();
   return true;
   return true;
 }
 }
 
 
-auto HandleTuplePatternStart(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleTuplePatternStart(Context& context,
+                             Parse::TuplePatternStartId parse_node) -> bool {
   // A tuple pattern following an implicit parameter list shares the same
   // A tuple pattern following an implicit parameter list shares the same
   // scope.
   // scope.
   //
   //

+ 6 - 4
toolchain/check/handle_return_statement.cpp

@@ -7,21 +7,23 @@
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
-auto HandleReturnStatementStart(Context& context, Parse::NodeId parse_node)
+auto HandleReturnStatementStart(Context& context,
+                                Parse::ReturnStatementStartId parse_node)
     -> bool {
     -> bool {
   // No action, just a bracketing node.
   // No action, just a bracketing node.
   context.node_stack().Push(parse_node);
   context.node_stack().Push(parse_node);
   return true;
   return true;
 }
 }
 
 
-auto HandleReturnVarModifier(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleReturnVarModifier(Context& context,
+                             Parse::ReturnVarModifierId parse_node) -> bool {
   // No action, just a bracketing node.
   // No action, just a bracketing node.
   context.node_stack().Push(parse_node);
   context.node_stack().Push(parse_node);
   return true;
   return true;
 }
 }
 
 
-auto HandleReturnStatement(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleReturnStatement(Context& context,
+                           Parse::ReturnStatementId parse_node) -> bool {
   switch (context.node_stack().PeekParseNodeKind()) {
   switch (context.node_stack().PeekParseNodeKind()) {
     case Parse::NodeKind::ReturnStatementStart:
     case Parse::NodeKind::ReturnStatementStart:
       // This is a `return;` statement.
       // This is a `return;` statement.

+ 14 - 10
toolchain/check/handle_struct.cpp

@@ -7,19 +7,22 @@
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
-auto HandleStructComma(Context& context, Parse::NodeId /*parse_node*/) -> bool {
+auto HandleStructComma(Context& context, Parse::StructCommaId /*parse_node*/)
+    -> bool {
   context.ParamOrArgComma();
   context.ParamOrArgComma();
   return true;
   return true;
 }
 }
 
 
-auto HandleStructFieldDesignator(Context& context, Parse::NodeId /*parse_node*/)
+auto HandleStructFieldDesignator(Context& context,
+                                 Parse::StructFieldDesignatorId /*parse_node*/)
     -> bool {
     -> bool {
   // This leaves the designated name on top because the `.` isn't interesting.
   // This leaves the designated name on top because the `.` isn't interesting.
   CARBON_CHECK(context.node_stack().PeekIsName());
   CARBON_CHECK(context.node_stack().PeekIsName());
   return true;
   return true;
 }
 }
 
 
-auto HandleStructFieldType(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleStructFieldType(Context& context,
+                           Parse::StructFieldTypeId parse_node) -> bool {
   auto [type_node, type_id] = context.node_stack().PopExprWithParseNode();
   auto [type_node, type_id] = context.node_stack().PopExprWithParseNode();
   SemIR::TypeId cast_type_id = ExprAsType(context, type_node, type_id);
   SemIR::TypeId cast_type_id = ExprAsType(context, type_node, type_id);
 
 
@@ -30,8 +33,8 @@ auto HandleStructFieldType(Context& context, Parse::NodeId parse_node) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleStructFieldValue(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleStructFieldValue(Context& context,
+                            Parse::StructFieldValueId parse_node) -> bool {
   auto value_inst_id = context.node_stack().PopExpr();
   auto value_inst_id = context.node_stack().PopExpr();
   auto [name_node, name_id] = context.node_stack().PopNameWithParseNode();
   auto [name_node, name_id] = context.node_stack().PopNameWithParseNode();
 
 
@@ -72,7 +75,8 @@ static auto DiagnoseDuplicateNames(Context& context,
   return false;
   return false;
 }
 }
 
 
-auto HandleStructLiteral(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleStructLiteral(Context& context, Parse::StructLiteralId parse_node)
+    -> bool {
   auto refs_id = context.ParamOrArgEnd(
   auto refs_id = context.ParamOrArgEnd(
       Parse::NodeKind::StructLiteralOrStructTypeLiteralStart);
       Parse::NodeKind::StructLiteralOrStructTypeLiteralStart);
 
 
@@ -94,8 +98,8 @@ auto HandleStructLiteral(Context& context, Parse::NodeId parse_node) -> bool {
   return true;
   return true;
 }
 }
 
 
-auto HandleStructLiteralOrStructTypeLiteralStart(Context& context,
-                                                 Parse::NodeId parse_node)
+auto HandleStructLiteralOrStructTypeLiteralStart(
+    Context& context, Parse::StructLiteralOrStructTypeLiteralStartId parse_node)
     -> bool {
     -> bool {
   context.PushScope();
   context.PushScope();
   context.node_stack().Push(parse_node);
   context.node_stack().Push(parse_node);
@@ -107,8 +111,8 @@ auto HandleStructLiteralOrStructTypeLiteralStart(Context& context,
   return true;
   return true;
 }
 }
 
 
-auto HandleStructTypeLiteral(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleStructTypeLiteral(Context& context,
+                             Parse::StructTypeLiteralId parse_node) -> bool {
   auto refs_id = context.ParamOrArgEnd(
   auto refs_id = context.ParamOrArgEnd(
       Parse::NodeKind::StructLiteralOrStructTypeLiteralStart);
       Parse::NodeKind::StructLiteralOrStructTypeLiteralStart);
 
 

+ 8 - 6
toolchain/check/handle_variable.cpp

@@ -9,29 +9,31 @@
 
 
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
-auto HandleVariableIntroducer(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleVariableIntroducer(Context& context,
+                              Parse::VariableIntroducerId parse_node) -> bool {
   // No action, just a bracketing node.
   // No action, just a bracketing node.
   context.node_stack().Push(parse_node);
   context.node_stack().Push(parse_node);
   context.decl_state_stack().Push(DeclState::Var);
   context.decl_state_stack().Push(DeclState::Var);
   return true;
   return true;
 }
 }
 
 
-auto HandleReturnedModifier(Context& context, Parse::NodeId parse_node)
-    -> bool {
+auto HandleReturnedModifier(Context& context,
+                            Parse::ReturnedModifierId parse_node) -> bool {
   // No action, just a bracketing node.
   // No action, just a bracketing node.
   context.node_stack().Push(parse_node);
   context.node_stack().Push(parse_node);
   return true;
   return true;
 }
 }
 
 
-auto HandleVariableInitializer(Context& context, Parse::NodeId parse_node)
+auto HandleVariableInitializer(Context& context,
+                               Parse::VariableInitializerId parse_node)
     -> bool {
     -> bool {
   // No action, just a bracketing node.
   // No action, just a bracketing node.
   context.node_stack().Push(parse_node);
   context.node_stack().Push(parse_node);
   return true;
   return true;
 }
 }
 
 
-auto HandleVariableDecl(Context& context, Parse::NodeId parse_node) -> bool {
+auto HandleVariableDecl(Context& context, Parse::VariableDeclId parse_node)
+    -> bool {
   // Handle the optional initializer.
   // Handle the optional initializer.
   auto init_id = SemIR::InstId::Invalid;
   auto init_id = SemIR::InstId::Invalid;
   Parse::NodeKind next_kind = context.node_stack().PeekParseNodeKind();
   Parse::NodeKind next_kind = context.node_stack().PeekParseNodeKind();

+ 4 - 5
toolchain/check/node_stack.h

@@ -92,20 +92,19 @@ class NodeStack {
   }
   }
 
 
   // Pops the top of the stack and returns the parse_node.
   // Pops the top of the stack and returns the parse_node.
-  // TODO: return a parse::NodeIdForKind<RequiredParseKind> instead.
   template <const Parse::NodeKind& RequiredParseKind>
   template <const Parse::NodeKind& RequiredParseKind>
-  auto PopForSoloParseNode() -> Parse::NodeId {
+  auto PopForSoloParseNode() -> Parse::NodeIdForKind<RequiredParseKind> {
     Entry back = PopEntry<SemIR::InstId>();
     Entry back = PopEntry<SemIR::InstId>();
     RequireIdKind(RequiredParseKind, IdKind::SoloParseNode);
     RequireIdKind(RequiredParseKind, IdKind::SoloParseNode);
     RequireParseKind<RequiredParseKind>(back.parse_node);
     RequireParseKind<RequiredParseKind>(back.parse_node);
-    return back.parse_node;
+    return Parse::NodeIdForKind<RequiredParseKind>(back.parse_node);
   }
   }
 
 
   // Pops the top of the stack if it is the given kind, and returns the
   // Pops the top of the stack if it is the given kind, and returns the
   // parse_node. Otherwise, returns std::nullopt.
   // parse_node. Otherwise, returns std::nullopt.
-  // TODO: Return a `Parse::NodeIdForKind<RequiredParseKind>` instead.
   template <const Parse::NodeKind& RequiredParseKind>
   template <const Parse::NodeKind& RequiredParseKind>
-  auto PopForSoloParseNodeIf() -> std::optional<Parse::NodeId> {
+  auto PopForSoloParseNodeIf()
+      -> std::optional<Parse::NodeIdForKind<RequiredParseKind>> {
     if (PeekIs<RequiredParseKind>()) {
     if (PeekIs<RequiredParseKind>()) {
       return PopForSoloParseNode<RequiredParseKind>();
       return PopForSoloParseNode<RequiredParseKind>();
     }
     }

+ 6 - 0
toolchain/parse/node_ids.h

@@ -50,6 +50,9 @@ struct NodeIdInCategory : public NodeId {
   // An explicitly invalid instance.
   // An explicitly invalid instance.
   static const NodeIdInCategory<Category> Invalid;
   static const NodeIdInCategory<Category> Invalid;
 
 
+  // TODO: Support conversion from `NodeIdForKind<Kind>` if `Kind::category()`
+  // overlaps with `Category`.
+
   explicit NodeIdInCategory(NodeId node_id) : NodeId(node_id) {}
   explicit NodeIdInCategory(NodeId node_id) : NodeId(node_id) {}
 };
 };
 
 
@@ -72,6 +75,9 @@ struct NodeIdOneOf : public NodeId {
   // An explicitly invalid instance.
   // An explicitly invalid instance.
   static const NodeIdOneOf<T, U> Invalid;
   static const NodeIdOneOf<T, U> Invalid;
 
 
+  // TODO: Support conversion from `NodeIdForKind<Kind>` if `Kind` is
+  // `T::Kind` or `U::Kind`.
+
   explicit NodeIdOneOf(NodeId node_id) : NodeId(node_id) {}
   explicit NodeIdOneOf(NodeId node_id) : NodeId(node_id) {}
 };
 };
 
 

+ 1 - 0
toolchain/sem_ir/typed_insts.h

@@ -18,6 +18,7 @@
 //   associated location. Almost all instructions should have this, with
 //   associated location. Almost all instructions should have this, with
 //   exceptions being things that are generated internally, without any relation
 //   exceptions being things that are generated internally, without any relation
 //   to source syntax, such as predeclared builtins.
 //   to source syntax, such as predeclared builtins.
+//   TODO: Make these typed parse node id types.
 // - Optionally, a `TypeId type_id;` member, for instructions that produce a
 // - Optionally, a `TypeId type_id;` member, for instructions that produce a
 //   value. This includes instructions that produce an abstract value, such as a
 //   value. This includes instructions that produce an abstract value, such as a
 //   `Namespace`, for which a placeholder type should be used.
 //   `Namespace`, for which a placeholder type should be used.