Kaynağa Gözat

Switch types to a SemanticsTypeId. (#2854)

This switches types to using SemanticsTypeId instead of SemanticsNodeId, and lowering pre-builds its list of types. The empty tuple type is special-cased because we don't want to emit it unless it's in-use, but as the implicit return for functions, it's frequently used. Callables use invalid to indicate the implicit return, and that seems undesirable to change due to the size increase.
Jon Ross-Perkins 2 yıl önce
ebeveyn
işleme
1497e1333d
71 değiştirilmiş dosya ile 645 ekleme ve 523 silme
  1. 6 6
      toolchain/driver/testdata/semantics_builtin_nodes.carbon
  2. 7 22
      toolchain/lowering/lowering_context.cpp
  3. 18 12
      toolchain/lowering/lowering_context.h
  4. 15 12
      toolchain/lowering/lowering_handle.cpp
  5. 35 30
      toolchain/semantics/semantics_context.cpp
  6. 8 8
      toolchain/semantics/semantics_context.h
  7. 6 6
      toolchain/semantics/semantics_handle.cpp
  8. 5 2
      toolchain/semantics/semantics_handle_function.cpp
  9. 3 6
      toolchain/semantics/semantics_handle_struct.cpp
  10. 6 5
      toolchain/semantics/semantics_ir.cpp
  11. 42 6
      toolchain/semantics/semantics_ir.h
  12. 16 16
      toolchain/semantics/semantics_ir_test.cpp
  13. 39 8
      toolchain/semantics/semantics_node.h
  14. 13 0
      toolchain/semantics/semantics_node_stack.cpp
  15. 13 2
      toolchain/semantics/semantics_node_stack.h
  16. 12 12
      toolchain/semantics/testdata/basics/builtin_types.carbon
  17. 1 0
      toolchain/semantics/testdata/basics/fail_name_lookup.carbon
  18. 5 5
      toolchain/semantics/testdata/designators/fail_unsupported.carbon
  19. 13 12
      toolchain/semantics/testdata/function/call/empty_struct.carbon
  20. 19 18
      toolchain/semantics/testdata/function/call/fail_param_count.carbon
  21. 5 4
      toolchain/semantics/testdata/function/call/fail_param_type.carbon
  22. 8 7
      toolchain/semantics/testdata/function/call/fail_return_type_mismatch.carbon
  23. 11 10
      toolchain/semantics/testdata/function/call/i32.carbon
  24. 19 18
      toolchain/semantics/testdata/function/call/more_param_ir.carbon
  25. 5 4
      toolchain/semantics/testdata/function/call/params_one.carbon
  26. 7 6
      toolchain/semantics/testdata/function/call/params_one_comma.carbon
  27. 9 8
      toolchain/semantics/testdata/function/call/params_two.carbon
  28. 13 12
      toolchain/semantics/testdata/function/call/params_two_comma.carbon
  29. 1 0
      toolchain/semantics/testdata/function/call/params_zero.carbon
  30. 5 4
      toolchain/semantics/testdata/function/definition/fail_param_name_conflict.carbon
  31. 1 0
      toolchain/semantics/testdata/function/definition/order.carbon
  32. 3 2
      toolchain/semantics/testdata/function/definition/params_one.carbon
  33. 3 2
      toolchain/semantics/testdata/function/definition/params_one_comma.carbon
  34. 5 4
      toolchain/semantics/testdata/function/definition/params_two.carbon
  35. 5 4
      toolchain/semantics/testdata/function/definition/params_two_comma.carbon
  36. 1 0
      toolchain/semantics/testdata/function/definition/params_zero.carbon
  37. 5 4
      toolchain/semantics/testdata/function/definition/same_param_name.carbon
  38. 5 5
      toolchain/semantics/testdata/operators/binary_op.carbon
  39. 5 5
      toolchain/semantics/testdata/operators/fail_type_mismatch.carbon
  40. 7 7
      toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon
  41. 3 3
      toolchain/semantics/testdata/return/fail_type_mismatch.carbon
  42. 3 2
      toolchain/semantics/testdata/return/fail_value_disallowed.carbon
  43. 1 1
      toolchain/semantics/testdata/return/fail_value_missing.carbon
  44. 1 0
      toolchain/semantics/testdata/return/no_value.carbon
  45. 9 9
      toolchain/semantics/testdata/return/struct.carbon
  46. 3 3
      toolchain/semantics/testdata/return/value.carbon
  47. 12 12
      toolchain/semantics/testdata/struct/empty.carbon
  48. 7 7
      toolchain/semantics/testdata/struct/fail_assign_empty.carbon
  49. 10 10
      toolchain/semantics/testdata/struct/fail_assign_to_empty.carbon
  50. 10 10
      toolchain/semantics/testdata/struct/fail_field_name_mismatch.carbon
  51. 10 10
      toolchain/semantics/testdata/struct/fail_field_type_mismatch.carbon
  52. 13 13
      toolchain/semantics/testdata/struct/fail_member_access_type.carbon
  53. 13 13
      toolchain/semantics/testdata/struct/fail_non_member_access.carbon
  54. 11 11
      toolchain/semantics/testdata/struct/fail_too_few_values.carbon
  55. 7 7
      toolchain/semantics/testdata/struct/fail_type_assign.carbon
  56. 7 7
      toolchain/semantics/testdata/struct/fail_value_as_type.carbon
  57. 21 21
      toolchain/semantics/testdata/struct/member_access.carbon
  58. 15 15
      toolchain/semantics/testdata/struct/one_entry.carbon
  59. 20 20
      toolchain/semantics/testdata/struct/two_entries.carbon
  60. 3 2
      toolchain/semantics/testdata/var/decl.carbon
  61. 5 4
      toolchain/semantics/testdata/var/decl_with_init.carbon
  62. 9 8
      toolchain/semantics/testdata/var/fail_duplicate_decl.carbon
  63. 5 4
      toolchain/semantics/testdata/var/fail_init_type_mismatch.carbon
  64. 4 3
      toolchain/semantics/testdata/var/fail_init_with_self.carbon
  65. 6 5
      toolchain/semantics/testdata/var/fail_lookup_outside_scope.carbon
  66. 6 5
      toolchain/semantics/testdata/var/fail_storage_is_literal.carbon
  67. 2 2
      toolchain/semantics/testdata/var/global_decl.carbon
  68. 4 4
      toolchain/semantics/testdata/var/global_decl_with_init.carbon
  69. 7 7
      toolchain/semantics/testdata/var/global_lookup.carbon
  70. 8 7
      toolchain/semantics/testdata/var/global_lookup_in_scope.carbon
  71. 5 4
      toolchain/semantics/testdata/var/lookup.carbon

+ 6 - 6
toolchain/driver/testdata/semantics_builtin_nodes.carbon

@@ -16,12 +16,12 @@
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: CrossReference, arg0: ir0, arg1: nodeTypeType, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: CrossReference, arg0: ir0, arg1: nodeInvalidType, type: nodeInvalidType},
-// CHECK:STDOUT:   {kind: CrossReference, arg0: ir0, arg1: nodeIntegerType, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: CrossReference, arg0: ir0, arg1: nodeFloatingPointType, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: CrossReference, arg0: ir0, arg1: nodeStringType, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: CrossReference, arg0: ir0, arg1: nodeEmptyTupleType, type: nodeTypeType},
+// CHECK:STDOUT:   {kind: CrossReference, arg0: ir0, arg1: nodeTypeType, type: typeTypeType},
+// CHECK:STDOUT:   {kind: CrossReference, arg0: ir0, arg1: nodeInvalidType, type: typeInvalidType},
+// CHECK:STDOUT:   {kind: CrossReference, arg0: ir0, arg1: nodeIntegerType, type: typeTypeType},
+// CHECK:STDOUT:   {kind: CrossReference, arg0: ir0, arg1: nodeFloatingPointType, type: typeTypeType},
+// CHECK:STDOUT:   {kind: CrossReference, arg0: ir0, arg1: nodeStringType, type: typeTypeType},
+// CHECK:STDOUT:   {kind: CrossReference, arg0: ir0, arg1: nodeEmptyTupleType, type: typeTypeType},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT:   [
 // CHECK:STDOUT:   [

+ 7 - 22
toolchain/lowering/lowering_context.cpp

@@ -23,6 +23,12 @@ LoweringContext::LoweringContext(llvm::LLVMContext& llvm_context,
       lowered_callables_(semantics_ir_->callables_size(), nullptr) {
       lowered_callables_(semantics_ir_->callables_size(), nullptr) {
   CARBON_CHECK(!semantics_ir.has_errors())
   CARBON_CHECK(!semantics_ir.has_errors())
       << "Generating LLVM IR from invalid SemanticsIR is unsupported.";
       << "Generating LLVM IR from invalid SemanticsIR is unsupported.";
+
+  auto types = semantics_ir_->types();
+  lowered_types_.resize_for_overwrite(types.size());
+  for (int i = 0; i < static_cast<int>(types.size()); ++i) {
+    lowered_types_[i] = BuildLoweredNodeAsType(types[i]);
+  }
 }
 }
 
 
 auto LoweringContext::Run() -> std::unique_ptr<llvm::Module> {
 auto LoweringContext::Run() -> std::unique_ptr<llvm::Module> {
@@ -86,7 +92,7 @@ auto LoweringContext::BuildLoweredNodeAsType(SemanticsNodeId node_id)
         // recursion while still letting them cache.
         // recursion while still letting them cache.
         CARBON_CHECK(type_id.index < SemanticsBuiltinKind::ValidCount)
         CARBON_CHECK(type_id.index < SemanticsBuiltinKind::ValidCount)
             << type_id;
             << type_id;
-        subtypes.push_back(GetLoweredNodeAsType(type_id));
+        subtypes.push_back(GetType(type_id));
       }
       }
       return llvm::StructType::create(*llvm_context_, subtypes,
       return llvm::StructType::create(*llvm_context_, subtypes,
                                       "StructLiteralType");
                                       "StructLiteralType");
@@ -97,25 +103,4 @@ auto LoweringContext::BuildLoweredNodeAsType(SemanticsNodeId node_id)
   }
   }
 }
 }
 
 
-auto LoweringContext::GetLoweredNodeAsType(SemanticsNodeId node_id)
-    -> llvm::Type* {
-  if (lowered_nodes_[node_id.index]) {
-    return lowered_nodes_[node_id.index].get<llvm::Type*>();
-  }
-
-  auto* type = BuildLoweredNodeAsType(node_id);
-  lowered_nodes_[node_id.index] = type;
-  return type;
-}
-
-auto LoweringContext::GetLoweredNodeAsValue(SemanticsNodeId node_id)
-    -> llvm::Value* {
-  auto& node = lowered_nodes_[node_id.index];
-  auto* value = node.dyn_cast<llvm::Value*>();
-  CARBON_CHECK(value != nullptr)
-      << node_id << " doesn't have a Value (either Type or null); nullness: "
-      << node.isNull();
-  return value;
-}
-
 }  // namespace Carbon
 }  // namespace Carbon

+ 18 - 12
toolchain/lowering/lowering_context.h

@@ -26,19 +26,25 @@ class LoweringContext {
   auto Run() -> std::unique_ptr<llvm::Module>;
   auto Run() -> std::unique_ptr<llvm::Module>;
 
 
   auto HasLoweredNode(SemanticsNodeId node_id) -> bool {
   auto HasLoweredNode(SemanticsNodeId node_id) -> bool {
-    return !lowered_nodes_[node_id.index].isNull();
+    return lowered_nodes_[node_id.index];
   }
   }
 
 
-  // Returns a type for the given node. May construct and cache the type
-  // if it hasn't yet been built.
-  auto GetLoweredNodeAsType(SemanticsNodeId node_id) -> llvm::Type*;
+  // Returns a lowered type for the given type_id.
+  auto GetType(SemanticsTypeId type_id) -> llvm::Type* {
+    // Neither TypeType nor InvalidType should be passed in.
+    CARBON_CHECK(type_id.index >= 0) << type_id;
+    return lowered_types_[type_id.index];
+  }
 
 
   // Returns a value for the given node.
   // Returns a value for the given node.
-  auto GetLoweredNodeAsValue(SemanticsNodeId node_id) -> llvm::Value*;
+  auto GetLoweredNodeAsValue(SemanticsNodeId node_id) -> llvm::Value* {
+    CARBON_CHECK(lowered_nodes_[node_id.index]) << node_id;
+    return lowered_nodes_[node_id.index];
+  }
 
 
   // Sets the value for the given node.
   // Sets the value for the given node.
   auto SetLoweredNodeAsValue(SemanticsNodeId node_id, llvm::Value* value) {
   auto SetLoweredNodeAsValue(SemanticsNodeId node_id, llvm::Value* value) {
-    CARBON_CHECK(lowered_nodes_[node_id.index].isNull()) << node_id;
+    CARBON_CHECK(!lowered_nodes_[node_id.index]) << node_id;
     lowered_nodes_[node_id.index] = value;
     lowered_nodes_[node_id.index] = value;
   }
   }
 
 
@@ -92,16 +98,16 @@ class LoweringContext {
   // Maps nodes in SemanticsIR to a lowered value. This will have one entry per
   // Maps nodes in SemanticsIR to a lowered value. This will have one entry per
   // node, and will be non-null when lowered. It's expected to be sparse during
   // node, and will be non-null when lowered. It's expected to be sparse during
   // execution because while expressions will have entries, statements won't.
   // execution because while expressions will have entries, statements won't.
-  // TODO: Long-term, we should examine the practical trade-offs of making this
-  // a map; a map may end up lower memory consumption, but a vector offers cache
-  // efficiency and better performance. As a consequence, the right choice is
-  // unclear.
-  llvm::SmallVector<llvm::PointerUnion<llvm::Type*, llvm::Value*>>
-      lowered_nodes_;
+  // TODO: This is transitioning to only track global and local values, rather
+  // than one large map for all nodes.
+  llvm::SmallVector<llvm::Value*> lowered_nodes_;
 
 
   // Maps callables to lowered functions. Semantics treats callables as the
   // Maps callables to lowered functions. Semantics treats callables as the
   // canonical form of a function, so lowering needs to do the same.
   // canonical form of a function, so lowering needs to do the same.
   llvm::SmallVector<llvm::Function*> lowered_callables_;
   llvm::SmallVector<llvm::Function*> lowered_callables_;
+
+  // Provides lowered versions of types.
+  llvm::SmallVector<llvm::Type*> lowered_types_;
 };
 };
 
 
 // Declare handlers for each SemanticsIR node.
 // Declare handlers for each SemanticsIR node.

+ 15 - 12
toolchain/lowering/lowering_handle.cpp

@@ -73,14 +73,14 @@ auto LoweringHandleFunctionDeclaration(LoweringContext& context,
   llvm::SmallVector<llvm::Type*> args;
   llvm::SmallVector<llvm::Type*> args;
   args.resize_for_overwrite(param_refs.size());
   args.resize_for_overwrite(param_refs.size());
   for (int i = 0; i < static_cast<int>(param_refs.size()); ++i) {
   for (int i = 0; i < static_cast<int>(param_refs.size()); ++i) {
-    args[i] = context.GetLoweredNodeAsType(
+    args[i] = context.GetType(
         context.semantics_ir().GetNode(param_refs[i]).type_id());
         context.semantics_ir().GetNode(param_refs[i]).type_id());
   }
   }
 
 
-  llvm::Type* return_type = context.GetLoweredNodeAsType(
-      callable.return_type_id.is_valid()
-          ? callable.return_type_id
-          : SemanticsNodeId::BuiltinEmptyTupleType);
+  llvm::Type* return_type =
+      context.GetType(callable.return_type_id.is_valid()
+                          ? callable.return_type_id
+                          : context.semantics_ir().empty_tuple_type_id());
   llvm::FunctionType* function_type =
   llvm::FunctionType* function_type =
       llvm::FunctionType::get(return_type, args, /*isVarArg=*/false);
       llvm::FunctionType::get(return_type, args, /*isVarArg=*/false);
   auto* function = llvm::Function::Create(
   auto* function = llvm::Function::Create(
@@ -162,11 +162,13 @@ auto LoweringHandleStructMemberAccess(LoweringContext& context,
                                       SemanticsNode node) -> void {
                                       SemanticsNode node) -> void {
   auto [struct_id, member_index] = node.GetAsStructMemberAccess();
   auto [struct_id, member_index] = node.GetAsStructMemberAccess();
   auto struct_type_id = context.semantics_ir().GetNode(struct_id).type_id();
   auto struct_type_id = context.semantics_ir().GetNode(struct_id).type_id();
-  auto* llvm_type = context.GetLoweredNodeAsType(struct_type_id);
+  auto* llvm_type = context.GetType(struct_type_id);
 
 
   // Get type information for member names.
   // Get type information for member names.
   auto type_refs = context.semantics_ir().GetNodeBlock(
   auto type_refs = context.semantics_ir().GetNodeBlock(
-      context.semantics_ir().GetNode(struct_type_id).GetAsStructType());
+      context.semantics_ir()
+          .GetNode(context.semantics_ir().GetType(struct_type_id))
+          .GetAsStructType());
   auto member_name = context.semantics_ir().GetString(
   auto member_name = context.semantics_ir().GetString(
       context.semantics_ir()
       context.semantics_ir()
           .GetNode(type_refs[member_index.index])
           .GetNode(type_refs[member_index.index])
@@ -193,7 +195,7 @@ auto LoweringHandleStructTypeField(LoweringContext& /*context*/,
 auto LoweringHandleStructValue(LoweringContext& context,
 auto LoweringHandleStructValue(LoweringContext& context,
                                SemanticsNodeId node_id, SemanticsNode node)
                                SemanticsNodeId node_id, SemanticsNode node)
     -> void {
     -> void {
-  auto* llvm_type = context.GetLoweredNodeAsType(node.type_id());
+  auto* llvm_type = context.GetType(node.type_id());
   auto* alloca = context.builder().CreateAlloca(
   auto* alloca = context.builder().CreateAlloca(
       llvm_type, /*ArraySize=*/nullptr, "StructLiteralValue");
       llvm_type, /*ArraySize=*/nullptr, "StructLiteralValue");
   context.SetLoweredNodeAsValue(node_id, alloca);
   context.SetLoweredNodeAsValue(node_id, alloca);
@@ -201,7 +203,9 @@ auto LoweringHandleStructValue(LoweringContext& context,
   auto refs = context.semantics_ir().GetNodeBlock(node.GetAsStructValue());
   auto refs = context.semantics_ir().GetNodeBlock(node.GetAsStructValue());
   // Get type information for member names.
   // Get type information for member names.
   auto type_refs = context.semantics_ir().GetNodeBlock(
   auto type_refs = context.semantics_ir().GetNodeBlock(
-      context.semantics_ir().GetNode(node.type_id()).GetAsStructType());
+      context.semantics_ir()
+          .GetNode(context.semantics_ir().GetType(node.type_id()))
+          .GetAsStructType());
   for (int i = 0; i < static_cast<int>(refs.size()); ++i) {
   for (int i = 0; i < static_cast<int>(refs.size()); ++i) {
     auto member_name = context.semantics_ir().GetString(
     auto member_name = context.semantics_ir().GetString(
         context.semantics_ir().GetNode(type_refs[i]).GetAsStructTypeField());
         context.semantics_ir().GetNode(type_refs[i]).GetAsStructTypeField());
@@ -226,9 +230,8 @@ auto LoweringHandleVarStorage(LoweringContext& context, SemanticsNodeId node_id,
   // requires either looking ahead for BindName or restructuring semantics,
   // requires either looking ahead for BindName or restructuring semantics,
   // either of which affects the destructuring due to the difference in
   // either of which affects the destructuring due to the difference in
   // storage?
   // storage?
-  auto* alloca = context.builder().CreateAlloca(
-      context.GetLoweredNodeAsType(node.type_id()), /*ArraySize=*/nullptr,
-      "var");
+  auto* alloca = context.builder().CreateAlloca(context.GetType(node.type_id()),
+                                                /*ArraySize=*/nullptr, "var");
   context.SetLoweredNodeAsValue(node_id, alloca);
   context.SetLoweredNodeAsValue(node_id, alloca);
 }
 }
 
 

+ 35 - 30
toolchain/semantics/semantics_context.cpp

@@ -36,8 +36,10 @@ SemanticsContext::SemanticsContext(const TokenizedBuffer& tokens,
                             vlog_stream) {
                             vlog_stream) {
   // Inserts the "Invalid" and "Type" types as "used types" so that
   // Inserts the "Invalid" and "Type" types as "used types" so that
   // canonicalization can skip them. We don't emit either for lowering.
   // canonicalization can skip them. We don't emit either for lowering.
-  canonical_types_.insert(SemanticsNodeId::BuiltinInvalidType);
-  canonical_types_.insert(SemanticsNodeId::BuiltinTypeType);
+  canonical_types_.insert(
+      {SemanticsNodeId::BuiltinInvalidType, SemanticsTypeId::InvalidType});
+  canonical_types_.insert(
+      {SemanticsNodeId::BuiltinTypeType, SemanticsTypeId::TypeType});
 }
 }
 
 
 auto SemanticsContext::TODO(ParseTree::Node parse_node, std::string label)
 auto SemanticsContext::TODO(ParseTree::Node parse_node, std::string label)
@@ -59,10 +61,6 @@ auto SemanticsContext::VerifyOnFinish() -> void {
 }
 }
 
 
 auto SemanticsContext::AddNode(SemanticsNode node) -> SemanticsNodeId {
 auto SemanticsContext::AddNode(SemanticsNode node) -> SemanticsNodeId {
-  CARBON_CHECK(!node.type_id().is_valid() ||
-               node.type_id() == SemanticsNodeId::BuiltinInvalidType ||
-               canonical_types_.contains(node.type_id()))
-      << "Added node without canonicalizing its type: " << node;
   auto block = node_block_stack_.PeekForAdd();
   auto block = node_block_stack_.PeekForAdd();
   CARBON_VLOG() << "AddNode " << block << ": " << node << "\n";
   CARBON_VLOG() << "AddNode " << block << ": " << node << "\n";
   return semantics_->AddNode(block, node);
   return semantics_->AddNode(block, node);
@@ -101,7 +99,7 @@ auto SemanticsContext::AddNameToLookupImpl(SemanticsStringId name_id,
 }
 }
 
 
 auto SemanticsContext::BindName(ParseTree::Node name_node,
 auto SemanticsContext::BindName(ParseTree::Node name_node,
-                                SemanticsNodeId type_id,
+                                SemanticsTypeId type_id,
                                 SemanticsNodeId target_id)
                                 SemanticsNodeId target_id)
     -> SemanticsStringId {
     -> SemanticsStringId {
   CARBON_CHECK(parse_tree_->node_kind(name_node) == ParseNodeKind::DeclaredName)
   CARBON_CHECK(parse_tree_->node_kind(name_node) == ParseNodeKind::DeclaredName)
@@ -211,8 +209,8 @@ auto SemanticsContext::ImplicitAsForArgs(
                         size_t, std::string, std::string);
                         size_t, std::string, std::string);
       diagnostic->Note(
       diagnostic->Note(
           param_parse_node, CallArgTypeMismatch, i,
           param_parse_node, CallArgTypeMismatch, i,
-          semantics_->StringifyNode(semantics_->GetNode(value_id).type_id()),
-          semantics_->StringifyNode(as_type_id));
+          semantics_->StringifyType(semantics_->GetNode(value_id).type_id()),
+          semantics_->StringifyType(as_type_id));
       return false;
       return false;
     }
     }
   }
   }
@@ -222,7 +220,7 @@ auto SemanticsContext::ImplicitAsForArgs(
 
 
 auto SemanticsContext::ImplicitAsRequired(ParseTree::Node parse_node,
 auto SemanticsContext::ImplicitAsRequired(ParseTree::Node parse_node,
                                           SemanticsNodeId value_id,
                                           SemanticsNodeId value_id,
-                                          SemanticsNodeId as_type_id)
+                                          SemanticsTypeId as_type_id)
     -> SemanticsNodeId {
     -> SemanticsNodeId {
   SemanticsNodeId output_value_id = value_id;
   SemanticsNodeId output_value_id = value_id;
   if (ImplicitAsImpl(value_id, as_type_id, &output_value_id) ==
   if (ImplicitAsImpl(value_id, as_type_id, &output_value_id) ==
@@ -234,15 +232,15 @@ auto SemanticsContext::ImplicitAsRequired(ParseTree::Node parse_node,
     emitter_
     emitter_
         ->Build(
         ->Build(
             parse_node, ImplicitAsConversionFailure,
             parse_node, ImplicitAsConversionFailure,
-            semantics_->StringifyNode(semantics_->GetNode(value_id).type_id()),
-            semantics_->StringifyNode(as_type_id))
+            semantics_->StringifyType(semantics_->GetNode(value_id).type_id()),
+            semantics_->StringifyType(as_type_id))
         .Emit();
         .Emit();
   }
   }
   return output_value_id;
   return output_value_id;
 }
 }
 
 
 auto SemanticsContext::ImplicitAsImpl(SemanticsNodeId value_id,
 auto SemanticsContext::ImplicitAsImpl(SemanticsNodeId value_id,
-                                      SemanticsNodeId as_type_id,
+                                      SemanticsTypeId as_type_id,
                                       SemanticsNodeId* output_value_id)
                                       SemanticsNodeId* output_value_id)
     -> ImplicitAsKind {
     -> ImplicitAsKind {
   // Start by making sure both sides are valid. If any part is invalid, the
   // Start by making sure both sides are valid. If any part is invalid, the
@@ -253,11 +251,11 @@ auto SemanticsContext::ImplicitAsImpl(SemanticsNodeId value_id,
   }
   }
   auto value = semantics_->GetNode(value_id);
   auto value = semantics_->GetNode(value_id);
   auto value_type_id = value.type_id();
   auto value_type_id = value.type_id();
-  if (value_type_id == SemanticsNodeId::BuiltinInvalidType) {
+  if (value_type_id == SemanticsTypeId::InvalidType) {
     return ImplicitAsKind::Identical;
     return ImplicitAsKind::Identical;
   }
   }
 
 
-  if (as_type_id == SemanticsNodeId::BuiltinInvalidType) {
+  if (as_type_id == SemanticsTypeId::InvalidType) {
     // Although the target type is invalid, this still changes the value.
     // Although the target type is invalid, this still changes the value.
     if (output_value_id != nullptr) {
     if (output_value_id != nullptr) {
       *output_value_id = SemanticsNodeId::BuiltinInvalidType;
       *output_value_id = SemanticsNodeId::BuiltinInvalidType;
@@ -270,7 +268,7 @@ auto SemanticsContext::ImplicitAsImpl(SemanticsNodeId value_id,
     return ImplicitAsKind::Identical;
     return ImplicitAsKind::Identical;
   }
   }
 
 
-  if (as_type_id == SemanticsNodeId::BuiltinTypeType) {
+  if (as_type_id == SemanticsTypeId::TypeType) {
     // TODO: When converting `()` to a type, the result is `() as Type`.
     // TODO: When converting `()` to a type, the result is `() as Type`.
     // Right now there is no tuple value support.
     // Right now there is no tuple value support.
 
 
@@ -278,21 +276,24 @@ auto SemanticsContext::ImplicitAsImpl(SemanticsNodeId value_id,
     if (value.kind() == SemanticsNodeKind::StructValue &&
     if (value.kind() == SemanticsNodeKind::StructValue &&
         value.GetAsStructValue() == SemanticsNodeBlockId::Empty) {
         value.GetAsStructValue() == SemanticsNodeBlockId::Empty) {
       if (output_value_id != nullptr) {
       if (output_value_id != nullptr) {
-        *output_value_id = value_type_id;
+        *output_value_id = semantics_->GetType(value_type_id);
       }
       }
       return ImplicitAsKind::Compatible;
       return ImplicitAsKind::Compatible;
     }
     }
   }
   }
 
 
-  auto value_type = semantics_->GetNode(value_type_id);
-  auto as_type = semantics_->GetNode(as_type_id);
-  if (CanImplicitAsStruct(value_type, as_type)) {
-    // Under the current implementation, struct types are only allowed to
-    // ImplicitAs when they're equivalent. What's really missing is type
-    // consolidation such that this would fall under the above `value_type_id ==
-    // as_type_id` case. In the future, this will need to handle actual
-    // conversions.
-    return ImplicitAsKind::Identical;
+  if (value_type_id != SemanticsTypeId::TypeType &&
+      as_type_id != SemanticsTypeId::TypeType) {
+    auto value_type = semantics_->GetNode(semantics_->GetType(value_type_id));
+    auto as_type = semantics_->GetNode(semantics_->GetType(as_type_id));
+    if (CanImplicitAsStruct(value_type, as_type)) {
+      // Under the current implementation, struct types are only allowed to
+      // ImplicitAs when they're equivalent. What's really missing is type
+      // consolidation such that this would fall under the above `value_type_id
+      // == as_type_id` case. In the future, this will need to handle actual
+      // conversions.
+      return ImplicitAsKind::Identical;
+    }
   }
   }
 
 
   if (output_value_id != nullptr) {
   if (output_value_id != nullptr) {
@@ -368,11 +369,15 @@ auto SemanticsContext::ParamOrArgSave(bool for_args) -> void {
 }
 }
 
 
 auto SemanticsContext::CanonicalizeType(SemanticsNodeId node_id)
 auto SemanticsContext::CanonicalizeType(SemanticsNodeId node_id)
-    -> SemanticsNodeId {
-  if (canonical_types_.insert(node_id).second) {
-    semantics_->AddType(node_id);
+    -> SemanticsTypeId {
+  auto it = canonical_types_.find(node_id);
+  if (it != canonical_types_.end()) {
+    return it->second;
   }
   }
-  return node_id;
+
+  auto type_id = semantics_->AddType(node_id);
+  CARBON_CHECK(canonical_types_.insert({node_id, type_id}).second);
+  return type_id;
 }
 }
 
 
 auto SemanticsContext::PrintForStackDump(llvm::raw_ostream& output) const
 auto SemanticsContext::PrintForStackDump(llvm::raw_ostream& output) const

+ 8 - 8
toolchain/semantics/semantics_context.h

@@ -50,7 +50,7 @@ class SemanticsContext {
   }
   }
 
 
   // Binds a DeclaredName to a target node with the given type.
   // Binds a DeclaredName to a target node with the given type.
-  auto BindName(ParseTree::Node name_node, SemanticsNodeId type_id,
+  auto BindName(ParseTree::Node name_node, SemanticsTypeId type_id,
                 SemanticsNodeId target_id) -> SemanticsStringId;
                 SemanticsNodeId target_id) -> SemanticsStringId;
 
 
   // Temporarily remove name lookup entries added by the `var`. These will be
   // Temporarily remove name lookup entries added by the `var`. These will be
@@ -91,18 +91,18 @@ class SemanticsContext {
   // updated `value_id`. Prints a diagnostic and returns an InvalidType if
   // updated `value_id`. Prints a diagnostic and returns an InvalidType if
   // unsupported.
   // unsupported.
   auto ImplicitAsRequired(ParseTree::Node parse_node, SemanticsNodeId value_id,
   auto ImplicitAsRequired(ParseTree::Node parse_node, SemanticsNodeId value_id,
-                          SemanticsNodeId as_type_id) -> SemanticsNodeId;
+                          SemanticsTypeId as_type_id) -> SemanticsNodeId;
 
 
   // Canonicalizes a type which is tracked as a single node.
   // Canonicalizes a type which is tracked as a single node.
   // TODO: This should eventually return a type ID.
   // TODO: This should eventually return a type ID.
-  auto CanonicalizeType(SemanticsNodeId node_id) -> SemanticsNodeId;
+  auto CanonicalizeType(SemanticsNodeId node_id) -> SemanticsTypeId;
 
 
   // Converts an expression for use as a type.
   // Converts an expression for use as a type.
   // TODO: This should eventually return a type ID.
   // TODO: This should eventually return a type ID.
   auto ExpressionAsType(ParseTree::Node parse_node, SemanticsNodeId value_id)
   auto ExpressionAsType(ParseTree::Node parse_node, SemanticsNodeId value_id)
-      -> SemanticsNodeId {
-    return CanonicalizeType(ImplicitAsRequired(
-        parse_node, value_id, SemanticsNodeId::BuiltinTypeType));
+      -> SemanticsTypeId {
+    return CanonicalizeType(
+        ImplicitAsRequired(parse_node, value_id, SemanticsTypeId::TypeType));
   }
   }
 
 
   // Starts handling parameters or arguments.
   // Starts handling parameters or arguments.
@@ -182,7 +182,7 @@ class SemanticsContext {
   //
   //
   // If `output_value_id` is not null, then it will be set if there is a need to
   // If `output_value_id` is not null, then it will be set if there is a need to
   // cast.
   // cast.
-  auto ImplicitAsImpl(SemanticsNodeId value_id, SemanticsNodeId as_type_id,
+  auto ImplicitAsImpl(SemanticsNodeId value_id, SemanticsTypeId as_type_id,
                       SemanticsNodeId* output_value_id) -> ImplicitAsKind;
                       SemanticsNodeId* output_value_id) -> ImplicitAsKind;
 
 
   // Returns true if the ImplicitAs can use struct conversion.
   // Returns true if the ImplicitAs can use struct conversion.
@@ -243,7 +243,7 @@ class SemanticsContext {
 
 
   // Tracks types which have been used, so that they aren't repeatedly added to
   // Tracks types which have been used, so that they aren't repeatedly added to
   // SemanticsIR.
   // SemanticsIR.
-  llvm::DenseSet<SemanticsNodeId> canonical_types_;
+  llvm::DenseMap<SemanticsNodeId, SemanticsTypeId> canonical_types_;
 };
 };
 
 
 // Parse node handlers. Returns false for unrecoverable errors.
 // Parse node handlers. Returns false for unrecoverable errors.

+ 6 - 6
toolchain/semantics/semantics_handle.cpp

@@ -75,7 +75,8 @@ auto SemanticsHandleDesignatorExpression(SemanticsContext& context,
 
 
   auto base_id = context.node_stack().PopForNodeId();
   auto base_id = context.node_stack().PopForNodeId();
   auto base = context.semantics().GetNode(base_id);
   auto base = context.semantics().GetNode(base_id);
-  auto base_type = context.semantics().GetNode(base.type_id());
+  auto base_type =
+      context.semantics().GetNode(context.semantics().GetType(base.type_id()));
 
 
   switch (base_type.kind()) {
   switch (base_type.kind()) {
     case SemanticsNodeKind::StructType: {
     case SemanticsNodeKind::StructType: {
@@ -95,7 +96,7 @@ auto SemanticsHandleDesignatorExpression(SemanticsContext& context,
                         "Type `{0}` does not have a member `{1}`.", std::string,
                         "Type `{0}` does not have a member `{1}`.", std::string,
                         llvm::StringRef);
                         llvm::StringRef);
       context.emitter().Emit(parse_node, DesignatorExpressionNameNotFound,
       context.emitter().Emit(parse_node, DesignatorExpressionNameNotFound,
-                             context.semantics().StringifyNode(base.type_id()),
+                             context.semantics().StringifyType(base.type_id()),
                              context.semantics().GetString(name_id));
                              context.semantics().GetString(name_id));
       break;
       break;
     }
     }
@@ -104,7 +105,7 @@ auto SemanticsHandleDesignatorExpression(SemanticsContext& context,
                         "Type `{0}` does not support designator expressions.",
                         "Type `{0}` does not support designator expressions.",
                         std::string);
                         std::string);
       context.emitter().Emit(parse_node, DesignatorExpressionUnsupported,
       context.emitter().Emit(parse_node, DesignatorExpressionUnsupported,
-                             context.semantics().StringifyNode(base.type_id()));
+                             context.semantics().StringifyType(base.type_id()));
       break;
       break;
     }
     }
   }
   }
@@ -364,8 +365,7 @@ auto SemanticsHandlePatternBinding(SemanticsContext& context,
                                    ParseTree::Node parse_node) -> bool {
                                    ParseTree::Node parse_node) -> bool {
   auto [type_node, parsed_type_id] =
   auto [type_node, parsed_type_id] =
       context.node_stack().PopForParseNodeAndNodeId();
       context.node_stack().PopForParseNodeAndNodeId();
-  SemanticsNodeId cast_type_id =
-      context.ExpressionAsType(type_node, parsed_type_id);
+  auto cast_type_id = context.ExpressionAsType(type_node, parsed_type_id);
 
 
   // Get the name.
   // Get the name.
   auto name_node = context.node_stack().PopForSoloParseNode();
   auto name_node = context.node_stack().PopForSoloParseNode();
@@ -414,7 +414,7 @@ auto SemanticsHandleReturnStatement(SemanticsContext& context,
                         "Must return a {0}.", std::string);
                         "Must return a {0}.", std::string);
       context.emitter()
       context.emitter()
           .Build(parse_node, ReturnStatementMissingExpression,
           .Build(parse_node, ReturnStatementMissingExpression,
-                 context.semantics().StringifyNode(callable.return_type_id))
+                 context.semantics().StringifyType(callable.return_type_id))
           .Emit();
           .Emit();
     }
     }
 
 

+ 5 - 2
toolchain/semantics/semantics_handle_function.cpp

@@ -34,11 +34,14 @@ auto SemanticsHandleFunctionDefinition(SemanticsContext& context,
 auto SemanticsHandleFunctionDefinitionStart(SemanticsContext& context,
 auto SemanticsHandleFunctionDefinitionStart(SemanticsContext& context,
                                             ParseTree::Node parse_node)
                                             ParseTree::Node parse_node)
     -> bool {
     -> bool {
-  SemanticsNodeId return_type_id = SemanticsNodeId::Invalid;
+  SemanticsTypeId return_type_id = SemanticsTypeId::Invalid;
   if (context.parse_tree().node_kind(context.node_stack().PeekParseNode()) ==
   if (context.parse_tree().node_kind(context.node_stack().PeekParseNode()) ==
       ParseNodeKind::ReturnType) {
       ParseNodeKind::ReturnType) {
     return_type_id =
     return_type_id =
-        context.node_stack().PopForNodeId(ParseNodeKind::ReturnType);
+        context.node_stack().PopForTypeId(ParseNodeKind::ReturnType);
+  } else {
+    // Canonicalize the empty tuple for the implicit return.
+    context.CanonicalizeType(SemanticsNodeId::BuiltinEmptyTupleType);
   }
   }
   auto param_refs_id =
   auto param_refs_id =
       context.node_stack().PopForNodeBlockId(ParseNodeKind::ParameterList);
       context.node_stack().PopForNodeBlockId(ParseNodeKind::ParameterList);

+ 3 - 6
toolchain/semantics/semantics_handle_struct.cpp

@@ -28,7 +28,7 @@ auto SemanticsHandleStructFieldDesignator(SemanticsContext& context,
 auto SemanticsHandleStructFieldType(SemanticsContext& context,
 auto SemanticsHandleStructFieldType(SemanticsContext& context,
                                     ParseTree::Node parse_node) -> bool {
                                     ParseTree::Node parse_node) -> bool {
   auto [type_node, type_id] = context.node_stack().PopForParseNodeAndNodeId();
   auto [type_node, type_id] = context.node_stack().PopForParseNodeAndNodeId();
-  SemanticsNodeId cast_type_id = context.ExpressionAsType(type_node, type_id);
+  SemanticsTypeId cast_type_id = context.ExpressionAsType(type_node, type_id);
 
 
   auto [name_node, name_id] = context.node_stack().PopForParseNodeAndNameId(
   auto [name_node, name_id] = context.node_stack().PopForParseNodeAndNameId(
       ParseNodeKind::DesignatedName);
       ParseNodeKind::DesignatedName);
@@ -80,9 +80,7 @@ auto SemanticsHandleStructLiteral(SemanticsContext& context,
   auto refs = context.semantics().GetNodeBlock(refs_id);
   auto refs = context.semantics().GetNodeBlock(refs_id);
   auto type_id =
   auto type_id =
       context.CanonicalizeType(context.AddNode(SemanticsNode::StructType::Make(
       context.CanonicalizeType(context.AddNode(SemanticsNode::StructType::Make(
-          parse_node,
-          context.CanonicalizeType(SemanticsNodeId::BuiltinTypeType),
-          type_block_id)));
+          parse_node, SemanticsTypeId::TypeType, type_block_id)));
 
 
   auto value_id = context.AddNode(
   auto value_id = context.AddNode(
       SemanticsNode::StructValue::Make(parse_node, type_id, refs_id));
       SemanticsNode::StructValue::Make(parse_node, type_id, refs_id));
@@ -117,8 +115,7 @@ auto SemanticsHandleStructTypeLiteral(SemanticsContext& context,
       << "{} is handled by StructLiteral.";
       << "{} is handled by StructLiteral.";
 
 
   auto type_id = context.AddNode(SemanticsNode::StructType::Make(
   auto type_id = context.AddNode(SemanticsNode::StructType::Make(
-      parse_node, context.CanonicalizeType(SemanticsNodeId::BuiltinTypeType),
-      refs_id));
+      parse_node, SemanticsTypeId::TypeType, refs_id));
   context.node_stack().Push(parse_node, type_id);
   context.node_stack().Push(parse_node, type_id);
   return true;
   return true;
 }
 }

+ 6 - 5
toolchain/semantics/semantics_ir.cpp

@@ -24,8 +24,8 @@ auto SemanticsIR::MakeBuiltinIR() -> SemanticsIR {
   semantics.nodes_.push_back(SemanticsNode::Builtin::Make(            \
   semantics.nodes_.push_back(SemanticsNode::Builtin::Make(            \
       SemanticsBuiltinKind::Name,                                     \
       SemanticsBuiltinKind::Name,                                     \
       SemanticsBuiltinKind::Name == SemanticsBuiltinKind::InvalidType \
       SemanticsBuiltinKind::Name == SemanticsBuiltinKind::InvalidType \
-          ? SemanticsNodeId::BuiltinInvalidType                       \
-          : SemanticsNodeId::BuiltinTypeType));
+          ? SemanticsTypeId::InvalidType                              \
+          : SemanticsTypeId::TypeType));
 #include "toolchain/semantics/semantics_builtin_kind.def"
 #include "toolchain/semantics/semantics_builtin_kind.def"
 
 
   CARBON_CHECK(semantics.node_blocks_.size() == 1)
   CARBON_CHECK(semantics.node_blocks_.size() == 1)
@@ -141,7 +141,7 @@ auto SemanticsIR::Print(llvm::raw_ostream& out, bool include_builtins) const
   out << "]\n";
   out << "]\n";
 }
 }
 
 
-auto SemanticsIR::StringifyNode(SemanticsNodeId node_id) -> std::string {
+auto SemanticsIR::StringifyType(SemanticsTypeId type_id) -> std::string {
   std::string str;
   std::string str;
   llvm::raw_string_ostream out(str);
   llvm::raw_string_ostream out(str);
 
 
@@ -151,7 +151,8 @@ auto SemanticsIR::StringifyNode(SemanticsNodeId node_id) -> std::string {
     // The index into node_id to print. Not used by all types.
     // The index into node_id to print. Not used by all types.
     int index = 0;
     int index = 0;
   };
   };
-  llvm::SmallVector<Step> steps = {{.node_id = node_id}};
+  llvm::SmallVector<Step> steps = {
+      {.node_id = GetTypeAllowBuiltinTypes(type_id)}};
 
 
   while (!steps.empty()) {
   while (!steps.empty()) {
     auto step = steps.pop_back_val();
     auto step = steps.pop_back_val();
@@ -190,7 +191,7 @@ auto SemanticsIR::StringifyNode(SemanticsNodeId node_id) -> std::string {
       }
       }
       case SemanticsNodeKind::StructTypeField: {
       case SemanticsNodeKind::StructTypeField: {
         out << "." << GetString(node.GetAsStructTypeField()) << ": ";
         out << "." << GetString(node.GetAsStructTypeField()) << ": ";
-        steps.push_back({.node_id = node.type_id()});
+        steps.push_back({.node_id = GetTypeAllowBuiltinTypes(node.type_id())});
         break;
         break;
       }
       }
       case SemanticsNodeKind::Assign:
       case SemanticsNodeKind::Assign:

+ 42 - 6
toolchain/semantics/semantics_ir.h

@@ -25,8 +25,7 @@ struct SemanticsCallable {
   // A block containing a single reference node per parameter.
   // A block containing a single reference node per parameter.
   SemanticsNodeBlockId param_refs_id;
   SemanticsNodeBlockId param_refs_id;
   // The return type. This will be invalid if the return type wasn't specified.
   // The return type. This will be invalid if the return type wasn't specified.
-  // The IR corresponding to the return type will be in a node block.
-  SemanticsNodeId return_type_id;
+  SemanticsTypeId return_type_id;
 };
 };
 
 
 struct SemanticsRealLiteral {
 struct SemanticsRealLiteral {
@@ -160,11 +159,40 @@ class SemanticsIR {
     return std::nullopt;
     return std::nullopt;
   }
   }
 
 
-  // Adds a type.
-  auto AddType(SemanticsNodeId node_id) -> void { types_.push_back(node_id); }
+  // Adds a type, returning an ID to reference it.
+  auto AddType(SemanticsNodeId node_id) -> SemanticsTypeId {
+    SemanticsTypeId type_id(types_.size());
+    types_.push_back(node_id);
+    if (node_id == SemanticsNodeId::BuiltinEmptyTupleType) {
+      CARBON_CHECK(!empty_tuple_type_id_.is_valid());
+      empty_tuple_type_id_ = type_id;
+    }
+    return type_id;
+  }
 
 
-  // Produces a string version of a node.
-  auto StringifyNode(SemanticsNodeId node_id) -> std::string;
+  // Gets the node ID for a type. This doesn't handle TypeType or InvalidType in
+  // order to avoid a check; callers that need that should use
+  // GetTypeAllowBuiltinTypes.
+  auto GetType(SemanticsTypeId type_id) const -> SemanticsNodeId {
+    // Double-check it's not called with TypeType or InvalidType.
+    CARBON_CHECK(type_id.index >= 0)
+        << "Invalid argument for GetType: " << type_id;
+    return types_[type_id.index];
+  }
+
+  auto GetTypeAllowBuiltinTypes(SemanticsTypeId type_id) const
+      -> SemanticsNodeId {
+    if (type_id == SemanticsTypeId::TypeType) {
+      return SemanticsNodeId::BuiltinTypeType;
+    } else if (type_id == SemanticsTypeId::InvalidType) {
+      return SemanticsNodeId::BuiltinInvalidType;
+    } else {
+      return GetType(type_id);
+    }
+  }
+
+  // Produces a string version of a type.
+  auto StringifyType(SemanticsTypeId type_id) -> std::string;
 
 
   auto callables_size() const -> int { return callables_.size(); }
   auto callables_size() const -> int { return callables_.size(); }
   auto nodes_size() const -> int { return nodes_.size(); }
   auto nodes_size() const -> int { return nodes_.size(); }
@@ -173,6 +201,10 @@ class SemanticsIR {
     return types_;
     return types_;
   }
   }
 
 
+  auto empty_tuple_type_id() const -> SemanticsTypeId {
+    return empty_tuple_type_id_;
+  }
+
   // The node blocks, for direct mutation.
   // The node blocks, for direct mutation.
   auto node_blocks() -> llvm::SmallVector<llvm::SmallVector<SemanticsNodeId>>& {
   auto node_blocks() -> llvm::SmallVector<llvm::SmallVector<SemanticsNodeId>>& {
     return node_blocks_;
     return node_blocks_;
@@ -217,6 +249,10 @@ class SemanticsIR {
   // by lowering.
   // by lowering.
   llvm::SmallVector<SemanticsNodeId> types_;
   llvm::SmallVector<SemanticsNodeId> types_;
 
 
+  // The type of the empty tuple. This is special-cased due to its use in
+  // implicit function returns.
+  SemanticsTypeId empty_tuple_type_id_ = SemanticsTypeId::Invalid;
+
   // All nodes. The first entries will always be cross-references to builtins,
   // All nodes. The first entries will always be cross-references to builtins,
   // at indices matching SemanticsBuiltinKind ordering.
   // at indices matching SemanticsBuiltinKind ordering.
   llvm::SmallVector<SemanticsNode> nodes_;
   llvm::SmallVector<SemanticsNode> nodes_;

+ 16 - 16
toolchain/semantics/semantics_ir_test.cpp

@@ -45,6 +45,7 @@ TEST(SemanticsIRTest, YAML) {
   // cross-references, so this code is only doing loose structural checks.
   // cross-references, so this code is only doing loose structural checks.
   auto node_id = Yaml::Scalar(MatchesRegex(R"(node\+\d+)"));
   auto node_id = Yaml::Scalar(MatchesRegex(R"(node\+\d+)"));
   auto node_builtin = Yaml::Scalar(MatchesRegex(R"(node\w+)"));
   auto node_builtin = Yaml::Scalar(MatchesRegex(R"(node\w+)"));
+  auto type_id = Yaml::Scalar(MatchesRegex(R"(type\d+)"));
 
 
   EXPECT_THAT(
   EXPECT_THAT(
       Yaml::Value::FromText(print_output),
       Yaml::Value::FromText(print_output),
@@ -55,22 +56,21 @@ TEST(SemanticsIRTest, YAML) {
           Pair("real_literals", Yaml::Sequence(IsEmpty())),
           Pair("real_literals", Yaml::Sequence(IsEmpty())),
           Pair("strings", Yaml::Sequence(ElementsAre("x"))),
           Pair("strings", Yaml::Sequence(ElementsAre("x"))),
           Pair("types", Yaml::Sequence(ElementsAre(node_builtin))),
           Pair("types", Yaml::Sequence(ElementsAre(node_builtin))),
-          Pair(
-              "nodes",
-              Yaml::Sequence(AllOf(
-                  // kind is required, other parts are optional.
-                  Each(Yaml::Mapping(Contains(Pair("kind", _)))),
-                  // A 0-arg node.
-                  Contains(Yaml::Mapping(ElementsAre(
-                      Pair("kind", "VarStorage"), Pair("type", node_builtin)))),
-                  // A 1-arg node.
-                  Contains(Yaml::Mapping(ElementsAre(
-                      Pair("kind", "IntegerLiteral"), Pair("arg0", "int0"),
-                      Pair("type", node_builtin)))),
-                  // A 2-arg node.
-                  Contains(Yaml::Mapping(ElementsAre(
-                      Pair("kind", "BindName"), Pair("arg0", "str0"),
-                      Pair("arg1", node_id), Pair("type", node_builtin))))))),
+          Pair("nodes",
+               Yaml::Sequence(AllOf(
+                   // kind is required, other parts are optional.
+                   Each(Yaml::Mapping(Contains(Pair("kind", _)))),
+                   // A 0-arg node.
+                   Contains(Yaml::Mapping(ElementsAre(
+                       Pair("kind", "VarStorage"), Pair("type", type_id)))),
+                   // A 1-arg node.
+                   Contains(Yaml::Mapping(ElementsAre(
+                       Pair("kind", "IntegerLiteral"), Pair("arg0", "int0"),
+                       Pair("type", type_id)))),
+                   // A 2-arg node.
+                   Contains(Yaml::Mapping(ElementsAre(
+                       Pair("kind", "BindName"), Pair("arg0", "str0"),
+                       Pair("arg1", node_id), Pair("type", type_id))))))),
           // This production has only one node block.
           // This production has only one node block.
           Pair("node_blocks",
           Pair("node_blocks",
                Yaml::Sequence(ElementsAre(Yaml::Sequence(IsEmpty()),
                Yaml::Sequence(ElementsAre(Yaml::Sequence(IsEmpty()),

+ 39 - 8
toolchain/semantics/semantics_node.h

@@ -115,6 +115,37 @@ struct SemanticsStringId : public IndexBase {
   }
   }
 };
 };
 
 
+// The ID of a node block.
+struct SemanticsTypeId : public IndexBase {
+  // The builtin TypeType.
+  static const SemanticsTypeId TypeType;
+
+  // The builtin InvalidType.
+  static const SemanticsTypeId InvalidType;
+
+  // An explicitly invalid ID.
+  static const SemanticsTypeId Invalid;
+
+  using IndexBase::IndexBase;
+  auto Print(llvm::raw_ostream& out) const -> void {
+    out << "type";
+    if (index == TypeType.index) {
+      out << "TypeType";
+    } else if (index == InvalidType.index) {
+      out << "InvalidType";
+    } else {
+      IndexBase::Print(out);
+    }
+  }
+};
+
+constexpr SemanticsTypeId SemanticsTypeId::TypeType =
+    SemanticsTypeId(SemanticsTypeId::InvalidIndex - 2);
+constexpr SemanticsTypeId SemanticsTypeId::InvalidType =
+    SemanticsTypeId(SemanticsTypeId::InvalidIndex - 1);
+constexpr SemanticsTypeId SemanticsTypeId::Invalid =
+    SemanticsTypeId(SemanticsTypeId::InvalidIndex);
+
 // An index for member access.
 // An index for member access.
 struct SemanticsMemberIndex : public IndexBase {
 struct SemanticsMemberIndex : public IndexBase {
   using IndexBase::IndexBase;
   using IndexBase::IndexBase;
@@ -160,7 +191,7 @@ class SemanticsNode {
   template <KindTemplateEnum Kind, typename... ArgTypes>
   template <KindTemplateEnum Kind, typename... ArgTypes>
   class FactoryBase {
   class FactoryBase {
    protected:
    protected:
-    static auto Make(ParseTree::Node parse_node, SemanticsNodeId type_id,
+    static auto Make(ParseTree::Node parse_node, SemanticsTypeId type_id,
                      ArgTypes... arg_ids) -> SemanticsNode {
                      ArgTypes... arg_ids) -> SemanticsNode {
       return SemanticsNode(parse_node, SemanticsNodeKind::Create(Kind), type_id,
       return SemanticsNode(parse_node, SemanticsNodeKind::Create(Kind), type_id,
                            arg_ids.index...);
                            arg_ids.index...);
@@ -204,7 +235,7 @@ class SemanticsNode {
    public:
    public:
     static auto Make(ParseTree::Node parse_node, ArgTypes... args) {
     static auto Make(ParseTree::Node parse_node, ArgTypes... args) {
       return FactoryBase<Kind, ArgTypes...>::Make(
       return FactoryBase<Kind, ArgTypes...>::Make(
-          parse_node, SemanticsNodeId::Invalid, args...);
+          parse_node, SemanticsTypeId::Invalid, args...);
     }
     }
     using FactoryBase<Kind, ArgTypes...>::Get;
     using FactoryBase<Kind, ArgTypes...>::Get;
   };
   };
@@ -233,7 +264,7 @@ class SemanticsNode {
 
 
   class Builtin {
   class Builtin {
    public:
    public:
-    static auto Make(SemanticsBuiltinKind builtin_kind, SemanticsNodeId type_id)
+    static auto Make(SemanticsBuiltinKind builtin_kind, SemanticsTypeId type_id)
         -> SemanticsNode {
         -> SemanticsNode {
       // Builtins won't have a ParseTree node associated, so we provide the
       // Builtins won't have a ParseTree node associated, so we provide the
       // default invalid one.
       // default invalid one.
@@ -259,7 +290,7 @@ class SemanticsNode {
                            SemanticsCrossReferenceIRId /*ir_id*/,
                            SemanticsCrossReferenceIRId /*ir_id*/,
                            SemanticsNodeId /*node_id*/> {
                            SemanticsNodeId /*node_id*/> {
    public:
    public:
-    static auto Make(SemanticsNodeId type_id, SemanticsCrossReferenceIRId ir_id,
+    static auto Make(SemanticsTypeId type_id, SemanticsCrossReferenceIRId ir_id,
                      SemanticsNodeId node_id) -> SemanticsNode {
                      SemanticsNodeId node_id) -> SemanticsNode {
       // A node's parse tree node must refer to a node in the current parse
       // A node's parse tree node must refer to a node in the current parse
       // tree. This cannot use the cross-referenced node's parse tree node
       // tree. This cannot use the cross-referenced node's parse tree node
@@ -314,7 +345,7 @@ class SemanticsNode {
 
 
   SemanticsNode()
   SemanticsNode()
       : SemanticsNode(ParseTree::Node::Invalid, SemanticsNodeKind::Invalid,
       : SemanticsNode(ParseTree::Node::Invalid, SemanticsNodeKind::Invalid,
-                      SemanticsNodeId::Invalid) {}
+                      SemanticsTypeId::Invalid) {}
 
 
   // Provide `node.GetAsKind()` as an instance method for all kinds, essentially
   // Provide `node.GetAsKind()` as an instance method for all kinds, essentially
   // an alias for`SemanticsNode::Kind::Get(node)`.
   // an alias for`SemanticsNode::Kind::Get(node)`.
@@ -324,7 +355,7 @@ class SemanticsNode {
 
 
   auto parse_node() const -> ParseTree::Node { return parse_node_; }
   auto parse_node() const -> ParseTree::Node { return parse_node_; }
   auto kind() const -> SemanticsNodeKind { return kind_; }
   auto kind() const -> SemanticsNodeKind { return kind_; }
-  auto type_id() const -> SemanticsNodeId { return type_id_; }
+  auto type_id() const -> SemanticsTypeId { return type_id_; }
 
 
   auto Print(llvm::raw_ostream& out) const -> void;
   auto Print(llvm::raw_ostream& out) const -> void;
 
 
@@ -334,7 +365,7 @@ class SemanticsNode {
   friend struct SemanticsNodeForBuiltin;
   friend struct SemanticsNodeForBuiltin;
 
 
   explicit SemanticsNode(ParseTree::Node parse_node, SemanticsNodeKind kind,
   explicit SemanticsNode(ParseTree::Node parse_node, SemanticsNodeKind kind,
-                         SemanticsNodeId type_id,
+                         SemanticsTypeId type_id,
                          int32_t arg0 = SemanticsNodeId::InvalidIndex,
                          int32_t arg0 = SemanticsNodeId::InvalidIndex,
                          int32_t arg1 = SemanticsNodeId::InvalidIndex)
                          int32_t arg1 = SemanticsNodeId::InvalidIndex)
       : parse_node_(parse_node),
       : parse_node_(parse_node),
@@ -345,7 +376,7 @@ class SemanticsNode {
 
 
   ParseTree::Node parse_node_;
   ParseTree::Node parse_node_;
   SemanticsNodeKind kind_;
   SemanticsNodeKind kind_;
-  SemanticsNodeId type_id_;
+  SemanticsTypeId type_id_;
 
 
   // Use GetAsKind to access arg0 and arg1.
   // Use GetAsKind to access arg0 and arg1.
   int32_t arg0_;
   int32_t arg0_;

+ 13 - 0
toolchain/semantics/semantics_node_stack.cpp

@@ -19,9 +19,15 @@ auto SemanticsNodeStack::PushEntry(Entry entry, DebugLog debug_log) -> void {
     case DebugLog::NodeId:
     case DebugLog::NodeId:
       CARBON_VLOG() << entry.node_id;
       CARBON_VLOG() << entry.node_id;
       break;
       break;
+    case DebugLog::NodeBlockId:
+      CARBON_VLOG() << entry.node_block_id;
+      break;
     case DebugLog::NameId:
     case DebugLog::NameId:
       CARBON_VLOG() << entry.name_id;
       CARBON_VLOG() << entry.name_id;
       break;
       break;
+    case DebugLog::TypeId:
+      CARBON_VLOG() << entry.type_id;
+      break;
   }
   }
   CARBON_VLOG() << "\n";
   CARBON_VLOG() << "\n";
   CARBON_CHECK(stack_.size() < (1 << 20))
   CARBON_CHECK(stack_.size() < (1 << 20))
@@ -137,6 +143,13 @@ auto SemanticsNodeStack::PopForNodeBlockId(ParseNodeKind pop_parse_kind)
   return back.node_block_id;
   return back.node_block_id;
 }
 }
 
 
+auto SemanticsNodeStack::PopForTypeId(ParseNodeKind pop_parse_kind)
+    -> SemanticsTypeId {
+  auto back = PopEntry(pop_parse_kind);
+  RequireValidId(back);
+  return back.type_id;
+}
+
 auto SemanticsNodeStack::PopForParseNodeAndNameId(ParseNodeKind pop_parse_kind)
 auto SemanticsNodeStack::PopForParseNodeAndNameId(ParseNodeKind pop_parse_kind)
     -> std::pair<ParseTree::Node, SemanticsStringId> {
     -> std::pair<ParseTree::Node, SemanticsStringId> {
   auto back = PopEntry(pop_parse_kind);
   auto back = PopEntry(pop_parse_kind);

+ 13 - 2
toolchain/semantics/semantics_node_stack.h

@@ -49,7 +49,7 @@ class SemanticsNodeStack {
   auto Push(ParseTree::Node parse_node, SemanticsNodeBlockId node_block_id)
   auto Push(ParseTree::Node parse_node, SemanticsNodeBlockId node_block_id)
       -> void {
       -> void {
     PushEntry({.parse_node = parse_node, .node_block_id = node_block_id},
     PushEntry({.parse_node = parse_node, .node_block_id = node_block_id},
-              DebugLog::NodeId);
+              DebugLog::NodeBlockId);
   }
   }
 
 
   // Pushes a parse tree node onto the stack with its name.
   // Pushes a parse tree node onto the stack with its name.
@@ -57,6 +57,11 @@ class SemanticsNodeStack {
     PushEntry({.parse_node = parse_node, .name_id = name_id}, DebugLog::NameId);
     PushEntry({.parse_node = parse_node, .name_id = name_id}, DebugLog::NameId);
   }
   }
 
 
+  // Pushes a parse tree node onto the stack with a semantics node block.
+  auto Push(ParseTree::Node parse_node, SemanticsTypeId type_id) -> void {
+    PushEntry({.parse_node = parse_node, .type_id = type_id}, DebugLog::TypeId);
+  }
+
   // Pops the top of the stack without any verification.
   // Pops the top of the stack without any verification.
   auto PopAndIgnore() -> void { PopEntry(); }
   auto PopAndIgnore() -> void { PopEntry(); }
 
 
@@ -92,6 +97,9 @@ class SemanticsNodeStack {
   // Pops the top of the stack and returns the node_block_id.
   // Pops the top of the stack and returns the node_block_id.
   auto PopForNodeBlockId(ParseNodeKind pop_parse_kind) -> SemanticsNodeBlockId;
   auto PopForNodeBlockId(ParseNodeKind pop_parse_kind) -> SemanticsNodeBlockId;
 
 
+  // Pops the top of the stack and returns the type_id.
+  auto PopForTypeId(ParseNodeKind pop_parse_kind) -> SemanticsTypeId;
+
   // Pops the top of the stack and returns the parse_node and name_id.
   // Pops the top of the stack and returns the parse_node and name_id.
   auto PopForParseNodeAndNameId(ParseNodeKind pop_parse_kind)
   auto PopForParseNodeAndNameId(ParseNodeKind pop_parse_kind)
       -> std::pair<ParseTree::Node, SemanticsStringId>;
       -> std::pair<ParseTree::Node, SemanticsStringId>;
@@ -121,8 +129,9 @@ class SemanticsNodeStack {
     // is used based on the ParseNodeKind.
     // is used based on the ParseNodeKind.
     union {
     union {
       SemanticsNodeId node_id;
       SemanticsNodeId node_id;
-      SemanticsStringId name_id;
       SemanticsNodeBlockId node_block_id;
       SemanticsNodeBlockId node_block_id;
+      SemanticsStringId name_id;
+      SemanticsTypeId type_id;
     };
     };
   };
   };
   static_assert(sizeof(Entry) == 8, "Unexpected Entry size");
   static_assert(sizeof(Entry) == 8, "Unexpected Entry size");
@@ -131,7 +140,9 @@ class SemanticsNodeStack {
   enum DebugLog {
   enum DebugLog {
     None,
     None,
     NodeId,
     NodeId,
+    NodeBlockId,
     NameId,
     NameId,
+    TypeId,
   };
   };
 
 
   // Pushes an entry onto the stack.
   // Pushes an entry onto the stack.

+ 12 - 12
toolchain/semantics/testdata/basics/builtin_types.carbon

@@ -24,18 +24,18 @@
 // CHECK:STDOUT:   nodeStringType,
 // CHECK:STDOUT:   nodeStringType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+0, arg1: node+2, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeFloatingPointType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+4, type: nodeFloatingPointType},
-// CHECK:STDOUT:   {kind: RealLiteral, arg0: real0, type: nodeFloatingPointType},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+4, arg1: node+6, type: nodeFloatingPointType},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeStringType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str2, arg1: node+8, type: nodeStringType},
-// CHECK:STDOUT:   {kind: StringLiteral, arg0: str3, type: nodeStringType},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+8, arg1: node+10, type: nodeStringType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: type0},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type0},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+0, arg1: node+2, type: type0},
+// CHECK:STDOUT:   {kind: VarStorage, type: type1},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+4, type: type1},
+// CHECK:STDOUT:   {kind: RealLiteral, arg0: real0, type: type1},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+4, arg1: node+6, type: type1},
+// CHECK:STDOUT:   {kind: VarStorage, type: type2},
+// CHECK:STDOUT:   {kind: BindName, arg0: str2, arg1: node+8, type: type2},
+// CHECK:STDOUT:   {kind: StringLiteral, arg0: str3, type: type2},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+8, arg1: node+10, type: type2},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT:   [
 // CHECK:STDOUT:   [

+ 1 - 0
toolchain/semantics/testdata/basics/fail_name_lookup.carbon

@@ -15,6 +15,7 @@
 // CHECK:STDOUT:   Main,
 // CHECK:STDOUT:   Main,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},

+ 5 - 5
toolchain/semantics/testdata/designators/fail_unsupported.carbon

@@ -19,11 +19,11 @@
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+2, arg1: nodeInvalidType, type: nodeInvalidType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: type0},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: type0},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+2, arg1: nodeInvalidType, type: typeInvalidType},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT:   [
 // CHECK:STDOUT:   [

+ 13 - 12
toolchain/semantics/testdata/function/call/empty_struct.carbon

@@ -5,7 +5,7 @@
 // AUTOUPDATE
 // AUTOUPDATE
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: callables: [
 // CHECK:STDOUT: callables: [
-// CHECK:STDOUT:   {param_refs: block2, return_type: node+4},
+// CHECK:STDOUT:   {param_refs: block2, return_type: type1},
 // CHECK:STDOUT:   {param_refs: block0},
 // CHECK:STDOUT:   {param_refs: block0},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: integer_literals: [
 // CHECK:STDOUT: integer_literals: [
@@ -20,23 +20,24 @@
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   node+0,
 // CHECK:STDOUT:   node+0,
 // CHECK:STDOUT:   node+4,
 // CHECK:STDOUT:   node+4,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   node+10,
 // CHECK:STDOUT:   node+10,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: StructType, arg0: block0, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: StructValue, arg0: block0, type: node+0},
-// CHECK:STDOUT:   {kind: VarStorage, type: node+0},
-// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+2, type: node+0},
-// CHECK:STDOUT:   {kind: StructType, arg0: block0, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: StructValue, arg0: block0, type: node+4},
+// CHECK:STDOUT:   {kind: StructType, arg0: block0, type: typeTypeType},
+// CHECK:STDOUT:   {kind: StructValue, arg0: block0, type: type0},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+2, type: type0},
+// CHECK:STDOUT:   {kind: StructType, arg0: block0, type: typeTypeType},
+// CHECK:STDOUT:   {kind: StructValue, arg0: block0, type: type1},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str1, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str1, arg1: callable0},
-// CHECK:STDOUT:   {kind: ReturnExpression, arg0: node+2, type: node+0},
+// CHECK:STDOUT:   {kind: ReturnExpression, arg0: node+2, type: type0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+6, arg1: block4},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+6, arg1: block4},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str2, arg1: callable1},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str2, arg1: callable1},
-// CHECK:STDOUT:   {kind: StructType, arg0: block0, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: StructValue, arg0: block0, type: node+10},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+11, type: node+10},
-// CHECK:STDOUT:   {kind: Call, arg0: block6, arg1: callable0, type: node+4},
+// CHECK:STDOUT:   {kind: StructType, arg0: block0, type: typeTypeType},
+// CHECK:STDOUT:   {kind: StructValue, arg0: block0, type: type3},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+11, type: type3},
+// CHECK:STDOUT:   {kind: Call, arg0: block6, arg1: callable0, type: type1},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+9, arg1: block5},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+9, arg1: block5},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [

+ 19 - 18
toolchain/semantics/testdata/function/call/fail_param_count.carbon

@@ -29,34 +29,35 @@
 // CHECK:STDOUT:   Main,
 // CHECK:STDOUT:   Main,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block0},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type1},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: type1},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str2, arg1: callable1},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str2, arg1: callable1},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+4, arg1: block0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+4, arg1: block0},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+6, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str3, arg1: node+8, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type1},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+6, type: type1},
+// CHECK:STDOUT:   {kind: VarStorage, type: type1},
+// CHECK:STDOUT:   {kind: BindName, arg0: str3, arg1: node+8, type: type1},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str4, arg1: callable2},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str4, arg1: callable2},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+10, arg1: block0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+10, arg1: block0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str5, arg1: callable3},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str5, arg1: callable3},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+13, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int1, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+15, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int2, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+17, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int3, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+19, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int4, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+21, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int5, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+23, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type1},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+13, type: type1},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int1, type: type1},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+15, type: type1},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int2, type: type1},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+17, type: type1},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int3, type: type1},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+19, type: type1},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int4, type: type1},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+21, type: type1},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int5, type: type1},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+23, type: type1},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+12, arg1: block6},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+12, arg1: block6},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [

+ 5 - 4
toolchain/semantics/testdata/function/call/fail_param_type.carbon

@@ -20,16 +20,17 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   nodeFloatingPointType,
 // CHECK:STDOUT:   nodeFloatingPointType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: type0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str1, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str1, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+2, arg1: block0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+2, arg1: block0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str2, arg1: callable1},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str2, arg1: callable1},
-// CHECK:STDOUT:   {kind: RealLiteral, arg0: real0, type: nodeFloatingPointType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+5, type: nodeFloatingPointType},
+// CHECK:STDOUT:   {kind: RealLiteral, arg0: real0, type: type2},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+5, type: type2},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+4, arg1: block4},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+4, arg1: block4},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [

+ 8 - 7
toolchain/semantics/testdata/function/call/fail_return_type_mismatch.carbon

@@ -5,7 +5,7 @@
 // AUTOUPDATE
 // AUTOUPDATE
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: callables: [
 // CHECK:STDOUT: callables: [
-// CHECK:STDOUT:   {param_refs: block0, return_type: nodeFloatingPointType},
+// CHECK:STDOUT:   {param_refs: block0, return_type: type0},
 // CHECK:STDOUT:   {param_refs: block0},
 // CHECK:STDOUT:   {param_refs: block0},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: integer_literals: [
 // CHECK:STDOUT: integer_literals: [
@@ -20,18 +20,19 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeFloatingPointType,
 // CHECK:STDOUT:   nodeFloatingPointType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
-// CHECK:STDOUT:   {kind: RealLiteral, arg0: real0, type: nodeFloatingPointType},
-// CHECK:STDOUT:   {kind: ReturnExpression, arg0: node+1, type: nodeFloatingPointType},
+// CHECK:STDOUT:   {kind: RealLiteral, arg0: real0, type: type0},
+// CHECK:STDOUT:   {kind: ReturnExpression, arg0: node+1, type: type0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str1, arg1: callable1},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str1, arg1: callable1},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str2, arg1: node+5, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: Call, arg0: block0, arg1: callable0, type: nodeFloatingPointType},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+5, arg1: nodeInvalidType, type: nodeInvalidType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type2},
+// CHECK:STDOUT:   {kind: BindName, arg0: str2, arg1: node+5, type: type2},
+// CHECK:STDOUT:   {kind: Call, arg0: block0, arg1: callable0, type: type0},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+5, arg1: nodeInvalidType, type: typeInvalidType},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+4, arg1: block3},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+4, arg1: block3},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [

+ 11 - 10
toolchain/semantics/testdata/function/call/i32.carbon

@@ -5,7 +5,7 @@
 // AUTOUPDATE
 // AUTOUPDATE
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: callables: [
 // CHECK:STDOUT: callables: [
-// CHECK:STDOUT:   {param_refs: block2, return_type: nodeIntegerType},
+// CHECK:STDOUT:   {param_refs: block2, return_type: type0},
 // CHECK:STDOUT:   {param_refs: block0},
 // CHECK:STDOUT:   {param_refs: block0},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: integer_literals: [
 // CHECK:STDOUT: integer_literals: [
@@ -21,20 +21,21 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: type0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str1, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str1, arg1: callable0},
-// CHECK:STDOUT:   {kind: ReturnExpression, arg0: node+0, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: ReturnExpression, arg0: node+0, type: type0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+2, arg1: block4},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+2, arg1: block4},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str2, arg1: callable1},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str2, arg1: callable1},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str3, arg1: node+6, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+8, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: Call, arg0: block6, arg1: callable0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+6, arg1: node+10, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str3, arg1: node+6, type: type0},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type0},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+8, type: type0},
+// CHECK:STDOUT:   {kind: Call, arg0: block6, arg1: callable0, type: type0},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+6, arg1: node+10, type: type0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+5, arg1: block5},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+5, arg1: block5},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [

+ 19 - 18
toolchain/semantics/testdata/function/call/more_param_ir.carbon

@@ -27,29 +27,30 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str2, arg1: node+4, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: type0},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: type0},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str2, arg1: node+4, type: type0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str3, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str3, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+6, arg1: block0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+6, arg1: block0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str4, arg1: callable1},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str4, arg1: callable1},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int1, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BinaryOperatorAdd, arg0: node+9, arg1: node+10, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int2, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BinaryOperatorAdd, arg0: node+11, arg1: node+12, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+13, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int3, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int4, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BinaryOperatorAdd, arg0: node+15, arg1: node+16, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+17, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int5, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+19, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type0},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int1, type: type0},
+// CHECK:STDOUT:   {kind: BinaryOperatorAdd, arg0: node+9, arg1: node+10, type: type0},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int2, type: type0},
+// CHECK:STDOUT:   {kind: BinaryOperatorAdd, arg0: node+11, arg1: node+12, type: type0},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+13, type: type0},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int3, type: type0},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int4, type: type0},
+// CHECK:STDOUT:   {kind: BinaryOperatorAdd, arg0: node+15, arg1: node+16, type: type0},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+17, type: type0},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int5, type: type0},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+19, type: type0},
 // CHECK:STDOUT:   {kind: Call, arg0: block5, arg1: callable0},
 // CHECK:STDOUT:   {kind: Call, arg0: block5, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+8, arg1: block4},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+8, arg1: block4},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]

+ 5 - 4
toolchain/semantics/testdata/function/call/params_one.carbon

@@ -20,15 +20,16 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: type0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str1, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str1, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+2, arg1: block0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+2, arg1: block0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str2, arg1: callable1},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str2, arg1: callable1},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+5, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type0},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+5, type: type0},
 // CHECK:STDOUT:   {kind: Call, arg0: block5, arg1: callable0},
 // CHECK:STDOUT:   {kind: Call, arg0: block5, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+4, arg1: block4},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+4, arg1: block4},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]

+ 7 - 6
toolchain/semantics/testdata/function/call/params_one_comma.carbon

@@ -21,18 +21,19 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: type0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str1, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str1, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+2, arg1: block0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+2, arg1: block0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str2, arg1: callable1},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str2, arg1: callable1},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+5, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type0},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+5, type: type0},
 // CHECK:STDOUT:   {kind: Call, arg0: block5, arg1: callable0},
 // CHECK:STDOUT:   {kind: Call, arg0: block5, arg1: callable0},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int1, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+8, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int1, type: type0},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+8, type: type0},
 // CHECK:STDOUT:   {kind: Call, arg0: block6, arg1: callable0},
 // CHECK:STDOUT:   {kind: Call, arg0: block6, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+4, arg1: block4},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+4, arg1: block4},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]

+ 9 - 8
toolchain/semantics/testdata/function/call/params_two.carbon

@@ -22,19 +22,20 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: type0},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: type0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str2, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str2, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+4, arg1: block0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+4, arg1: block0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str3, arg1: callable1},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str3, arg1: callable1},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+7, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int1, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+9, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type0},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+7, type: type0},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int1, type: type0},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+9, type: type0},
 // CHECK:STDOUT:   {kind: Call, arg0: block5, arg1: callable0},
 // CHECK:STDOUT:   {kind: Call, arg0: block5, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+6, arg1: block4},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+6, arg1: block4},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]

+ 13 - 12
toolchain/semantics/testdata/function/call/params_two_comma.carbon

@@ -24,24 +24,25 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: type0},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: type0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str2, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str2, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+4, arg1: block0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+4, arg1: block0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str3, arg1: callable1},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str3, arg1: callable1},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+7, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int1, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+9, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type0},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+7, type: type0},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int1, type: type0},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+9, type: type0},
 // CHECK:STDOUT:   {kind: Call, arg0: block5, arg1: callable0},
 // CHECK:STDOUT:   {kind: Call, arg0: block5, arg1: callable0},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int2, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+12, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int3, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+14, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int2, type: type0},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+12, type: type0},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int3, type: type0},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+14, type: type0},
 // CHECK:STDOUT:   {kind: Call, arg0: block6, arg1: callable0},
 // CHECK:STDOUT:   {kind: Call, arg0: block6, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+6, arg1: block4},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+6, arg1: block4},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]

+ 1 - 0
toolchain/semantics/testdata/function/call/params_zero.carbon

@@ -17,6 +17,7 @@
 // CHECK:STDOUT:   Main,
 // CHECK:STDOUT:   Main,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},

+ 5 - 4
toolchain/semantics/testdata/function/definition/fail_param_name_conflict.carbon

@@ -17,12 +17,13 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+2, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: type0},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+2, type: type0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str1, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str1, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+4, arg1: block0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+4, arg1: block0},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]

+ 1 - 0
toolchain/semantics/testdata/function/definition/order.carbon

@@ -19,6 +19,7 @@
 // CHECK:STDOUT:   Baz,
 // CHECK:STDOUT:   Baz,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},

+ 3 - 2
toolchain/semantics/testdata/function/definition/params_one.carbon

@@ -17,10 +17,11 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: type0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str1, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str1, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+2, arg1: block0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+2, arg1: block0},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]

+ 3 - 2
toolchain/semantics/testdata/function/definition/params_one_comma.carbon

@@ -17,10 +17,11 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: type0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str1, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str1, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+2, arg1: block0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+2, arg1: block0},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]

+ 5 - 4
toolchain/semantics/testdata/function/definition/params_two.carbon

@@ -18,12 +18,13 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: type0},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: type0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str2, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str2, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+4, arg1: block0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+4, arg1: block0},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]

+ 5 - 4
toolchain/semantics/testdata/function/definition/params_two_comma.carbon

@@ -18,12 +18,13 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: type0},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: type0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str2, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str2, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+4, arg1: block0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+4, arg1: block0},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]

+ 1 - 0
toolchain/semantics/testdata/function/definition/params_zero.carbon

@@ -15,6 +15,7 @@
 // CHECK:STDOUT:   Foo,
 // CHECK:STDOUT:   Foo,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},

+ 5 - 4
toolchain/semantics/testdata/function/definition/same_param_name.carbon

@@ -19,14 +19,15 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: type0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str1, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str1, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+2, arg1: block0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+2, arg1: block0},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+4, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+4, type: type0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str2, arg1: callable1},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str2, arg1: callable1},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+6, arg1: block0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+6, arg1: block0},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]

+ 5 - 5
toolchain/semantics/testdata/operators/binary_op.carbon

@@ -5,7 +5,7 @@
 // AUTOUPDATE
 // AUTOUPDATE
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: callables: [
 // CHECK:STDOUT: callables: [
-// CHECK:STDOUT:   {param_refs: block0, return_type: nodeIntegerType},
+// CHECK:STDOUT:   {param_refs: block0, return_type: type0},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: integer_literals: [
 // CHECK:STDOUT: integer_literals: [
 // CHECK:STDOUT:   12,
 // CHECK:STDOUT:   12,
@@ -21,10 +21,10 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int1, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BinaryOperatorAdd, arg0: node+1, arg1: node+2, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: ReturnExpression, arg0: node+3, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type0},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int1, type: type0},
+// CHECK:STDOUT:   {kind: BinaryOperatorAdd, arg0: node+1, arg1: node+2, type: type0},
+// CHECK:STDOUT:   {kind: ReturnExpression, arg0: node+3, type: type0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [

+ 5 - 5
toolchain/semantics/testdata/operators/fail_type_mismatch.carbon

@@ -5,7 +5,7 @@
 // AUTOUPDATE
 // AUTOUPDATE
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: callables: [
 // CHECK:STDOUT: callables: [
-// CHECK:STDOUT:   {param_refs: block0, return_type: nodeIntegerType},
+// CHECK:STDOUT:   {param_refs: block0, return_type: type0},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: integer_literals: [
 // CHECK:STDOUT: integer_literals: [
 // CHECK:STDOUT:   12,
 // CHECK:STDOUT:   12,
@@ -22,10 +22,10 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: RealLiteral, arg0: real0, type: nodeFloatingPointType},
-// CHECK:STDOUT:   {kind: BinaryOperatorAdd, arg0: nodeInvalidType, arg1: node+2, type: nodeInvalidType},
-// CHECK:STDOUT:   {kind: ReturnExpression, arg0: node+3, type: nodeInvalidType},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type0},
+// CHECK:STDOUT:   {kind: RealLiteral, arg0: real0, type: type1},
+// CHECK:STDOUT:   {kind: BinaryOperatorAdd, arg0: nodeInvalidType, arg1: node+2, type: typeInvalidType},
+// CHECK:STDOUT:   {kind: ReturnExpression, arg0: node+3, type: typeInvalidType},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [

+ 7 - 7
toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon

@@ -5,7 +5,7 @@
 // AUTOUPDATE
 // AUTOUPDATE
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: callables: [
 // CHECK:STDOUT: callables: [
-// CHECK:STDOUT:   {param_refs: block0, return_type: nodeIntegerType},
+// CHECK:STDOUT:   {param_refs: block0, return_type: type0},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: integer_literals: [
 // CHECK:STDOUT: integer_literals: [
 // CHECK:STDOUT:   12,
 // CHECK:STDOUT:   12,
@@ -23,12 +23,12 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: RealLiteral, arg0: real0, type: nodeFloatingPointType},
-// CHECK:STDOUT:   {kind: BinaryOperatorAdd, arg0: nodeInvalidType, arg1: node+2, type: nodeInvalidType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int1, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BinaryOperatorAdd, arg0: node+3, arg1: node+4, type: nodeInvalidType},
-// CHECK:STDOUT:   {kind: ReturnExpression, arg0: node+5, type: nodeInvalidType},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type0},
+// CHECK:STDOUT:   {kind: RealLiteral, arg0: real0, type: type1},
+// CHECK:STDOUT:   {kind: BinaryOperatorAdd, arg0: nodeInvalidType, arg1: node+2, type: typeInvalidType},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int1, type: type0},
+// CHECK:STDOUT:   {kind: BinaryOperatorAdd, arg0: node+3, arg1: node+4, type: typeInvalidType},
+// CHECK:STDOUT:   {kind: ReturnExpression, arg0: node+5, type: typeInvalidType},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [

+ 3 - 3
toolchain/semantics/testdata/return/fail_type_mismatch.carbon

@@ -5,7 +5,7 @@
 // AUTOUPDATE
 // AUTOUPDATE
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: callables: [
 // CHECK:STDOUT: callables: [
-// CHECK:STDOUT:   {param_refs: block0, return_type: nodeIntegerType},
+// CHECK:STDOUT:   {param_refs: block0, return_type: type0},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: integer_literals: [
 // CHECK:STDOUT: integer_literals: [
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
@@ -21,8 +21,8 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
-// CHECK:STDOUT:   {kind: RealLiteral, arg0: real0, type: nodeFloatingPointType},
-// CHECK:STDOUT:   {kind: ReturnExpression, arg0: nodeInvalidType, type: nodeInvalidType},
+// CHECK:STDOUT:   {kind: RealLiteral, arg0: real0, type: type1},
+// CHECK:STDOUT:   {kind: ReturnExpression, arg0: nodeInvalidType, type: typeInvalidType},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [

+ 3 - 2
toolchain/semantics/testdata/return/fail_value_disallowed.carbon

@@ -16,12 +16,13 @@
 // CHECK:STDOUT:   Main,
 // CHECK:STDOUT:   Main,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: ReturnExpression, arg0: node+1, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type1},
+// CHECK:STDOUT:   {kind: ReturnExpression, arg0: node+1, type: type1},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [

+ 1 - 1
toolchain/semantics/testdata/return/fail_value_missing.carbon

@@ -5,7 +5,7 @@
 // AUTOUPDATE
 // AUTOUPDATE
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: callables: [
 // CHECK:STDOUT: callables: [
-// CHECK:STDOUT:   {param_refs: block0, return_type: nodeIntegerType},
+// CHECK:STDOUT:   {param_refs: block0, return_type: type0},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: integer_literals: [
 // CHECK:STDOUT: integer_literals: [
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]

+ 1 - 0
toolchain/semantics/testdata/return/no_value.carbon

@@ -15,6 +15,7 @@
 // CHECK:STDOUT:   Main,
 // CHECK:STDOUT:   Main,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},

+ 9 - 9
toolchain/semantics/testdata/return/struct.carbon

@@ -5,7 +5,7 @@
 // AUTOUPDATE
 // AUTOUPDATE
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: callables: [
 // CHECK:STDOUT: callables: [
-// CHECK:STDOUT:   {param_refs: block0, return_type: node+1},
+// CHECK:STDOUT:   {param_refs: block0, return_type: type1},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: integer_literals: [
 // CHECK:STDOUT: integer_literals: [
 // CHECK:STDOUT:   3,
 // CHECK:STDOUT:   3,
@@ -22,15 +22,15 @@
 // CHECK:STDOUT:   node+6,
 // CHECK:STDOUT:   node+6,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: nodeTypeType},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: type0},
+// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: typeTypeType},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str1, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str1, arg1: callable0},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+3, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block4, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: StructValue, arg0: block5, type: node+6},
-// CHECK:STDOUT:   {kind: ReturnExpression, arg0: node+7, type: node+6},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type0},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: type0},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+3, type: type0},
+// CHECK:STDOUT:   {kind: StructType, arg0: block4, type: typeTypeType},
+// CHECK:STDOUT:   {kind: StructValue, arg0: block5, type: type2},
+// CHECK:STDOUT:   {kind: ReturnExpression, arg0: node+7, type: type2},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+2, arg1: block3},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+2, arg1: block3},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [

+ 3 - 3
toolchain/semantics/testdata/return/value.carbon

@@ -5,7 +5,7 @@
 // AUTOUPDATE
 // AUTOUPDATE
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: callables: [
 // CHECK:STDOUT: callables: [
-// CHECK:STDOUT:   {param_refs: block0, return_type: nodeIntegerType},
+// CHECK:STDOUT:   {param_refs: block0, return_type: type0},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: integer_literals: [
 // CHECK:STDOUT: integer_literals: [
 // CHECK:STDOUT:   0,
 // CHECK:STDOUT:   0,
@@ -20,8 +20,8 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: ReturnExpression, arg0: node+1, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type0},
+// CHECK:STDOUT:   {kind: ReturnExpression, arg0: node+1, type: type0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [

+ 12 - 12
toolchain/semantics/testdata/struct/empty.carbon

@@ -20,18 +20,18 @@
 // CHECK:STDOUT:   node+7,
 // CHECK:STDOUT:   node+7,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: StructType, arg0: block0, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: StructValue, arg0: block0, type: node+0},
-// CHECK:STDOUT:   {kind: VarStorage, type: node+0},
-// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+2, type: node+0},
-// CHECK:STDOUT:   {kind: StructType, arg0: block0, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: StructValue, arg0: block0, type: node+4},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+2, arg1: node+5, type: node+4},
-// CHECK:STDOUT:   {kind: StructType, arg0: block0, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: StructValue, arg0: block0, type: node+7},
-// CHECK:STDOUT:   {kind: VarStorage, type: node+7},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+9, type: node+7},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+9, arg1: node+2, type: node+0},
+// CHECK:STDOUT:   {kind: StructType, arg0: block0, type: typeTypeType},
+// CHECK:STDOUT:   {kind: StructValue, arg0: block0, type: type0},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+2, type: type0},
+// CHECK:STDOUT:   {kind: StructType, arg0: block0, type: typeTypeType},
+// CHECK:STDOUT:   {kind: StructValue, arg0: block0, type: type1},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+2, arg1: node+5, type: type1},
+// CHECK:STDOUT:   {kind: StructType, arg0: block0, type: typeTypeType},
+// CHECK:STDOUT:   {kind: StructValue, arg0: block0, type: type2},
+// CHECK:STDOUT:   {kind: VarStorage, type: type2},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+9, type: type2},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+9, arg1: node+2, type: type0},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT:   [
 // CHECK:STDOUT:   [

+ 7 - 7
toolchain/semantics/testdata/struct/fail_assign_empty.carbon

@@ -20,13 +20,13 @@
 // CHECK:STDOUT:   node+4,
 // CHECK:STDOUT:   node+4,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: VarStorage, type: node+1},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: node+1},
-// CHECK:STDOUT:   {kind: StructType, arg0: block0, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: StructValue, arg0: block0, type: node+4},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+2, arg1: nodeInvalidType, type: nodeInvalidType},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: type0},
+// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: typeTypeType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type1},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: type1},
+// CHECK:STDOUT:   {kind: StructType, arg0: block0, type: typeTypeType},
+// CHECK:STDOUT:   {kind: StructValue, arg0: block0, type: type2},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+2, arg1: nodeInvalidType, type: typeInvalidType},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT:   [
 // CHECK:STDOUT:   [

+ 10 - 10
toolchain/semantics/testdata/struct/fail_assign_to_empty.carbon

@@ -21,16 +21,16 @@
 // CHECK:STDOUT:   node+7,
 // CHECK:STDOUT:   node+7,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: StructType, arg0: block0, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: StructValue, arg0: block0, type: node+0},
-// CHECK:STDOUT:   {kind: VarStorage, type: node+0},
-// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+2, type: node+0},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str1, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+4, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: StructValue, arg0: block3, type: node+7},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+2, arg1: nodeInvalidType, type: nodeInvalidType},
+// CHECK:STDOUT:   {kind: StructType, arg0: block0, type: typeTypeType},
+// CHECK:STDOUT:   {kind: StructValue, arg0: block0, type: type0},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+2, type: type0},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type1},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str1, type: type1},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+4, type: type1},
+// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: typeTypeType},
+// CHECK:STDOUT:   {kind: StructValue, arg0: block3, type: type2},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+2, arg1: nodeInvalidType, type: typeInvalidType},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT:   [
 // CHECK:STDOUT:   [

+ 10 - 10
toolchain/semantics/testdata/struct/fail_field_name_mismatch.carbon

@@ -22,16 +22,16 @@
 // CHECK:STDOUT:   node+7,
 // CHECK:STDOUT:   node+7,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: VarStorage, type: node+1},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: node+1},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str2, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+4, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block3, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: StructValue, arg0: block4, type: node+7},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+2, arg1: nodeInvalidType, type: nodeInvalidType},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: type0},
+// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: typeTypeType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type1},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: type1},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type0},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str2, type: type0},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+4, type: type0},
+// CHECK:STDOUT:   {kind: StructType, arg0: block3, type: typeTypeType},
+// CHECK:STDOUT:   {kind: StructValue, arg0: block4, type: type2},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+2, arg1: nodeInvalidType, type: typeInvalidType},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT:   [
 // CHECK:STDOUT:   [

+ 10 - 10
toolchain/semantics/testdata/struct/fail_field_type_mismatch.carbon

@@ -23,16 +23,16 @@
 // CHECK:STDOUT:   node+7,
 // CHECK:STDOUT:   node+7,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: VarStorage, type: node+1},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: node+1},
-// CHECK:STDOUT:   {kind: RealLiteral, arg0: real0, type: nodeFloatingPointType},
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str2, type: nodeFloatingPointType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+4, type: nodeFloatingPointType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block3, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: StructValue, arg0: block4, type: node+7},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+2, arg1: nodeInvalidType, type: nodeInvalidType},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: type0},
+// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: typeTypeType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type1},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: type1},
+// CHECK:STDOUT:   {kind: RealLiteral, arg0: real0, type: type2},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str2, type: type2},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+4, type: type2},
+// CHECK:STDOUT:   {kind: StructType, arg0: block3, type: typeTypeType},
+// CHECK:STDOUT:   {kind: StructValue, arg0: block4, type: type3},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+2, arg1: nodeInvalidType, type: typeInvalidType},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT:   [
 // CHECK:STDOUT:   [

+ 13 - 13
toolchain/semantics/testdata/struct/fail_member_access_type.carbon

@@ -24,19 +24,19 @@
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: nodeFloatingPointType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: VarStorage, type: node+1},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: node+1},
-// CHECK:STDOUT:   {kind: RealLiteral, arg0: real0, type: nodeFloatingPointType},
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: nodeFloatingPointType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+4, type: nodeFloatingPointType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block3, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: StructValue, arg0: block4, type: node+7},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+2, arg1: node+8, type: node+7},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str2, arg1: node+10, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+10, arg1: nodeInvalidType, type: nodeInvalidType},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: type0},
+// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: typeTypeType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type1},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: type1},
+// CHECK:STDOUT:   {kind: RealLiteral, arg0: real0, type: type0},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: type0},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+4, type: type0},
+// CHECK:STDOUT:   {kind: StructType, arg0: block3, type: typeTypeType},
+// CHECK:STDOUT:   {kind: StructValue, arg0: block4, type: type2},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+2, arg1: node+8, type: type2},
+// CHECK:STDOUT:   {kind: VarStorage, type: type3},
+// CHECK:STDOUT:   {kind: BindName, arg0: str2, arg1: node+10, type: type3},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+10, arg1: nodeInvalidType, type: typeInvalidType},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT:   [
 // CHECK:STDOUT:   [

+ 13 - 13
toolchain/semantics/testdata/struct/fail_non_member_access.carbon

@@ -23,19 +23,19 @@
 // CHECK:STDOUT:   node+7,
 // CHECK:STDOUT:   node+7,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: VarStorage, type: node+1},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: node+1},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+4, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block3, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: StructValue, arg0: block4, type: node+7},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+2, arg1: node+8, type: node+7},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str2, arg1: node+10, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+10, arg1: nodeInvalidType, type: nodeInvalidType},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: type0},
+// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: typeTypeType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type1},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: type1},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type0},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: type0},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+4, type: type0},
+// CHECK:STDOUT:   {kind: StructType, arg0: block3, type: typeTypeType},
+// CHECK:STDOUT:   {kind: StructValue, arg0: block4, type: type2},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+2, arg1: node+8, type: type2},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str2, arg1: node+10, type: type0},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+10, arg1: nodeInvalidType, type: typeInvalidType},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT:   [
 // CHECK:STDOUT:   [

+ 11 - 11
toolchain/semantics/testdata/struct/fail_too_few_values.carbon

@@ -22,17 +22,17 @@
 // CHECK:STDOUT:   node+8,
 // CHECK:STDOUT:   node+8,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str1, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: VarStorage, type: node+2},
-// CHECK:STDOUT:   {kind: BindName, arg0: str2, arg1: node+3, type: node+2},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+5, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block3, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: StructValue, arg0: block4, type: node+8},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+3, arg1: nodeInvalidType, type: nodeInvalidType},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: type0},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str1, type: type0},
+// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: typeTypeType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type1},
+// CHECK:STDOUT:   {kind: BindName, arg0: str2, arg1: node+3, type: type1},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type0},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: type0},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+5, type: type0},
+// CHECK:STDOUT:   {kind: StructType, arg0: block3, type: typeTypeType},
+// CHECK:STDOUT:   {kind: StructValue, arg0: block4, type: type2},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+3, arg1: nodeInvalidType, type: typeInvalidType},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT:   [
 // CHECK:STDOUT:   [

+ 7 - 7
toolchain/semantics/testdata/struct/fail_type_assign.carbon

@@ -19,13 +19,13 @@
 // CHECK:STDOUT:   node+1,
 // CHECK:STDOUT:   node+1,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: VarStorage, type: node+1},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: node+1},
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block3, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+2, arg1: nodeInvalidType, type: nodeInvalidType},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: type0},
+// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: typeTypeType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type1},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: type1},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: type0},
+// CHECK:STDOUT:   {kind: StructType, arg0: block3, type: typeTypeType},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+2, arg1: nodeInvalidType, type: typeInvalidType},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT:   [
 // CHECK:STDOUT:   [

+ 7 - 7
toolchain/semantics/testdata/struct/fail_value_as_type.carbon

@@ -20,13 +20,13 @@
 // CHECK:STDOUT:   node+3,
 // CHECK:STDOUT:   node+3,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: StructValue, arg0: block3, type: node+3},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeInvalidType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+5, type: nodeInvalidType},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type0},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: type0},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+0, type: type0},
+// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: typeTypeType},
+// CHECK:STDOUT:   {kind: StructValue, arg0: block3, type: type1},
+// CHECK:STDOUT:   {kind: VarStorage, type: typeInvalidType},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+5, type: typeInvalidType},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT:   [
 // CHECK:STDOUT:   [

+ 21 - 21
toolchain/semantics/testdata/struct/member_access.carbon

@@ -26,27 +26,27 @@
 // CHECK:STDOUT:   node+11,
 // CHECK:STDOUT:   node+11,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: nodeFloatingPointType},
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str1, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: VarStorage, type: node+2},
-// CHECK:STDOUT:   {kind: BindName, arg0: str2, arg1: node+3, type: node+2},
-// CHECK:STDOUT:   {kind: RealLiteral, arg0: real0, type: nodeFloatingPointType},
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: nodeFloatingPointType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+5, type: nodeFloatingPointType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str1, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+8, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block3, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: StructValue, arg0: block4, type: node+11},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+3, arg1: node+12, type: node+11},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str3, arg1: node+14, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructMemberAccess, arg0: node+3, arg1: member1, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+14, arg1: node+16, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str4, arg1: node+18, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+18, arg1: node+14, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: type0},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str1, type: type1},
+// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: typeTypeType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type2},
+// CHECK:STDOUT:   {kind: BindName, arg0: str2, arg1: node+3, type: type2},
+// CHECK:STDOUT:   {kind: RealLiteral, arg0: real0, type: type0},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: type0},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+5, type: type0},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type1},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str1, type: type1},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+8, type: type1},
+// CHECK:STDOUT:   {kind: StructType, arg0: block3, type: typeTypeType},
+// CHECK:STDOUT:   {kind: StructValue, arg0: block4, type: type3},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+3, arg1: node+12, type: type3},
+// CHECK:STDOUT:   {kind: VarStorage, type: type1},
+// CHECK:STDOUT:   {kind: BindName, arg0: str3, arg1: node+14, type: type1},
+// CHECK:STDOUT:   {kind: StructMemberAccess, arg0: node+3, arg1: member1, type: type1},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+14, arg1: node+16, type: type1},
+// CHECK:STDOUT:   {kind: VarStorage, type: type1},
+// CHECK:STDOUT:   {kind: BindName, arg0: str4, arg1: node+18, type: type1},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+18, arg1: node+14, type: type1},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT:   [
 // CHECK:STDOUT:   [

+ 15 - 15
toolchain/semantics/testdata/struct/one_entry.carbon

@@ -23,21 +23,21 @@
 // CHECK:STDOUT:   node+11,
 // CHECK:STDOUT:   node+11,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: VarStorage, type: node+1},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: node+1},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+4, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block3, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: StructValue, arg0: block4, type: node+7},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+2, arg1: node+8, type: node+7},
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block5, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: VarStorage, type: node+11},
-// CHECK:STDOUT:   {kind: BindName, arg0: str2, arg1: node+12, type: node+11},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+12, arg1: node+2, type: node+1},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: type0},
+// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: typeTypeType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type1},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: type1},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type0},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: type0},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+4, type: type0},
+// CHECK:STDOUT:   {kind: StructType, arg0: block3, type: typeTypeType},
+// CHECK:STDOUT:   {kind: StructValue, arg0: block4, type: type2},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+2, arg1: node+8, type: type2},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: type0},
+// CHECK:STDOUT:   {kind: StructType, arg0: block5, type: typeTypeType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type3},
+// CHECK:STDOUT:   {kind: BindName, arg0: str2, arg1: node+12, type: type3},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+12, arg1: node+2, type: type1},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT:   [
 // CHECK:STDOUT:   [

+ 20 - 20
toolchain/semantics/testdata/struct/two_entries.carbon

@@ -25,26 +25,26 @@
 // CHECK:STDOUT:   node+16,
 // CHECK:STDOUT:   node+16,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str1, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: VarStorage, type: node+2},
-// CHECK:STDOUT:   {kind: BindName, arg0: str2, arg1: node+3, type: node+2},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+5, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int1, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str1, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StubReference, arg0: node+8, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block3, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: StructValue, arg0: block4, type: node+11},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+3, arg1: node+12, type: node+11},
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructTypeField, arg0: str1, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: StructType, arg0: block5, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: VarStorage, type: node+16},
-// CHECK:STDOUT:   {kind: BindName, arg0: str3, arg1: node+17, type: node+16},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+17, arg1: node+3, type: node+2},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: type0},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str1, type: type0},
+// CHECK:STDOUT:   {kind: StructType, arg0: block2, type: typeTypeType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type1},
+// CHECK:STDOUT:   {kind: BindName, arg0: str2, arg1: node+3, type: type1},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type0},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: type0},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+5, type: type0},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int1, type: type0},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str1, type: type0},
+// CHECK:STDOUT:   {kind: StubReference, arg0: node+8, type: type0},
+// CHECK:STDOUT:   {kind: StructType, arg0: block3, type: typeTypeType},
+// CHECK:STDOUT:   {kind: StructValue, arg0: block4, type: type2},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+3, arg1: node+12, type: type2},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str0, type: type0},
+// CHECK:STDOUT:   {kind: StructTypeField, arg0: str1, type: type0},
+// CHECK:STDOUT:   {kind: StructType, arg0: block5, type: typeTypeType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type3},
+// CHECK:STDOUT:   {kind: BindName, arg0: str3, arg1: node+17, type: type3},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+17, arg1: node+3, type: type1},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT:   [
 // CHECK:STDOUT:   [

+ 3 - 2
toolchain/semantics/testdata/var/decl.carbon

@@ -16,12 +16,13 @@
 // CHECK:STDOUT:   x,
 // CHECK:STDOUT:   x,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+1, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type1},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+1, type: type1},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [

+ 5 - 4
toolchain/semantics/testdata/var/decl_with_init.carbon

@@ -17,14 +17,15 @@
 // CHECK:STDOUT:   x,
 // CHECK:STDOUT:   x,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+1, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+1, arg1: node+3, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type1},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+1, type: type1},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type1},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+1, arg1: node+3, type: type1},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [

+ 9 - 8
toolchain/semantics/testdata/var/fail_duplicate_decl.carbon

@@ -18,18 +18,19 @@
 // CHECK:STDOUT:   x,
 // CHECK:STDOUT:   x,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+1, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+1, arg1: node+3, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+5, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int1, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+1, arg1: node+7, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type1},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+1, type: type1},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type1},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+1, arg1: node+3, type: type1},
+// CHECK:STDOUT:   {kind: VarStorage, type: type1},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+5, type: type1},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int1, type: type1},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+1, arg1: node+7, type: type1},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [

+ 5 - 4
toolchain/semantics/testdata/var/fail_init_type_mismatch.carbon

@@ -17,15 +17,16 @@
 // CHECK:STDOUT:   x,
 // CHECK:STDOUT:   x,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeFloatingPointType,
 // CHECK:STDOUT:   nodeFloatingPointType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+1, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: RealLiteral, arg0: real0, type: nodeFloatingPointType},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+1, arg1: nodeInvalidType, type: nodeInvalidType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type1},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+1, type: type1},
+// CHECK:STDOUT:   {kind: RealLiteral, arg0: real0, type: type2},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+1, arg1: nodeInvalidType, type: typeInvalidType},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [

+ 4 - 3
toolchain/semantics/testdata/var/fail_init_with_self.carbon

@@ -16,13 +16,14 @@
 // CHECK:STDOUT:   x,
 // CHECK:STDOUT:   x,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+1, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+1, arg1: nodeInvalidType, type: nodeInvalidType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type1},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+1, type: type1},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+1, arg1: nodeInvalidType, type: typeInvalidType},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [

+ 6 - 5
toolchain/semantics/testdata/var/fail_lookup_outside_scope.carbon

@@ -17,16 +17,17 @@
 // CHECK:STDOUT:   y,
 // CHECK:STDOUT:   y,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+1, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type1},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+1, type: type1},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str2, arg1: node+4, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+4, arg1: nodeInvalidType, type: nodeInvalidType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type1},
+// CHECK:STDOUT:   {kind: BindName, arg0: str2, arg1: node+4, type: type1},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+4, arg1: nodeInvalidType, type: typeInvalidType},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT:   [
 // CHECK:STDOUT:   [

+ 6 - 5
toolchain/semantics/testdata/var/fail_storage_is_literal.carbon

@@ -18,15 +18,16 @@
 // CHECK:STDOUT:   x,
 // CHECK:STDOUT:   x,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeInvalidType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: nodeInvalidType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int1, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+2, arg1: nodeInvalidType, type: nodeInvalidType},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type1},
+// CHECK:STDOUT:   {kind: VarStorage, type: typeInvalidType},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+2, type: typeInvalidType},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int1, type: type1},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+2, arg1: nodeInvalidType, type: typeInvalidType},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [

+ 2 - 2
toolchain/semantics/testdata/var/global_decl.carbon

@@ -17,8 +17,8 @@
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: type0},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT:   [
 // CHECK:STDOUT:   [

+ 4 - 4
toolchain/semantics/testdata/var/global_decl_with_init.carbon

@@ -18,10 +18,10 @@
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+0, arg1: node+2, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: type0},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type0},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+0, arg1: node+2, type: type0},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT:   [
 // CHECK:STDOUT:   [

+ 7 - 7
toolchain/semantics/testdata/var/global_lookup.carbon

@@ -19,13 +19,13 @@
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+0, arg1: node+2, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+4, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+4, arg1: node+0, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: type0},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type0},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+0, arg1: node+2, type: type0},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+4, type: type0},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+4, arg1: node+0, type: type0},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT:   [
 // CHECK:STDOUT:   [

+ 8 - 7
toolchain/semantics/testdata/var/global_lookup_in_scope.carbon

@@ -19,16 +19,17 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+0, arg1: node+2, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str0, arg1: node+0, type: type0},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type0},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+0, arg1: node+2, type: type0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str1, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str1, arg1: callable0},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str2, arg1: node+5, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+5, arg1: node+0, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type0},
+// CHECK:STDOUT:   {kind: BindName, arg0: str2, arg1: node+5, type: type0},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+5, arg1: node+0, type: type0},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+4, arg1: block2},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+4, arg1: block2},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [

+ 5 - 4
toolchain/semantics/testdata/var/lookup.carbon

@@ -17,14 +17,15 @@
 // CHECK:STDOUT:   x,
 // CHECK:STDOUT:   x,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
-// CHECK:STDOUT:   {kind: VarStorage, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+1, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType},
-// CHECK:STDOUT:   {kind: Assign, arg0: node+1, arg1: node+3, type: nodeIntegerType},
+// CHECK:STDOUT:   {kind: VarStorage, type: type1},
+// CHECK:STDOUT:   {kind: BindName, arg0: str1, arg1: node+1, type: type1},
+// CHECK:STDOUT:   {kind: IntegerLiteral, arg0: int0, type: type1},
+// CHECK:STDOUT:   {kind: Assign, arg0: node+1, arg1: node+3, type: type1},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT:   {kind: FunctionDefinition, arg0: node+0, arg1: block2},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [