Просмотр исходного кода

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 лет назад
Родитель
Сommit
1497e1333d
71 измененных файлов с 645 добавлено и 523 удалено
  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: ]
 // 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: node_blocks: [
 // 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) {
   CARBON_CHECK(!semantics_ir.has_errors())
       << "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> {
@@ -86,7 +92,7 @@ auto LoweringContext::BuildLoweredNodeAsType(SemanticsNodeId node_id)
         // recursion while still letting them cache.
         CARBON_CHECK(type_id.index < SemanticsBuiltinKind::ValidCount)
             << type_id;
-        subtypes.push_back(GetLoweredNodeAsType(type_id));
+        subtypes.push_back(GetType(type_id));
       }
       return llvm::StructType::create(*llvm_context_, subtypes,
                                       "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

+ 18 - 12
toolchain/lowering/lowering_context.h

@@ -26,19 +26,25 @@ class LoweringContext {
   auto Run() -> std::unique_ptr<llvm::Module>;
 
   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.
-  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.
   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;
   }
 
@@ -92,16 +98,16 @@ class LoweringContext {
   // 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
   // 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
   // canonical form of a function, so lowering needs to do the same.
   llvm::SmallVector<llvm::Function*> lowered_callables_;
+
+  // Provides lowered versions of types.
+  llvm::SmallVector<llvm::Type*> lowered_types_;
 };
 
 // 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;
   args.resize_for_overwrite(param_refs.size());
   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());
   }
 
-  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::get(return_type, args, /*isVarArg=*/false);
   auto* function = llvm::Function::Create(
@@ -162,11 +162,13 @@ auto LoweringHandleStructMemberAccess(LoweringContext& context,
                                       SemanticsNode node) -> void {
   auto [struct_id, member_index] = node.GetAsStructMemberAccess();
   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.
   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(
       context.semantics_ir()
           .GetNode(type_refs[member_index.index])
@@ -193,7 +195,7 @@ auto LoweringHandleStructTypeField(LoweringContext& /*context*/,
 auto LoweringHandleStructValue(LoweringContext& context,
                                SemanticsNodeId node_id, SemanticsNode node)
     -> void {
-  auto* llvm_type = context.GetLoweredNodeAsType(node.type_id());
+  auto* llvm_type = context.GetType(node.type_id());
   auto* alloca = context.builder().CreateAlloca(
       llvm_type, /*ArraySize=*/nullptr, "StructLiteralValue");
   context.SetLoweredNodeAsValue(node_id, alloca);
@@ -201,7 +203,9 @@ auto LoweringHandleStructValue(LoweringContext& context,
   auto refs = context.semantics_ir().GetNodeBlock(node.GetAsStructValue());
   // Get type information for member names.
   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) {
     auto member_name = context.semantics_ir().GetString(
         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,
   // either of which affects the destructuring due to the difference in
   // 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);
 }
 

+ 35 - 30
toolchain/semantics/semantics_context.cpp

@@ -36,8 +36,10 @@ SemanticsContext::SemanticsContext(const TokenizedBuffer& tokens,
                             vlog_stream) {
   // Inserts the "Invalid" and "Type" types as "used types" so that
   // 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)
@@ -59,10 +61,6 @@ auto SemanticsContext::VerifyOnFinish() -> void {
 }
 
 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();
   CARBON_VLOG() << "AddNode " << block << ": " << node << "\n";
   return semantics_->AddNode(block, node);
@@ -101,7 +99,7 @@ auto SemanticsContext::AddNameToLookupImpl(SemanticsStringId name_id,
 }
 
 auto SemanticsContext::BindName(ParseTree::Node name_node,
-                                SemanticsNodeId type_id,
+                                SemanticsTypeId type_id,
                                 SemanticsNodeId target_id)
     -> SemanticsStringId {
   CARBON_CHECK(parse_tree_->node_kind(name_node) == ParseNodeKind::DeclaredName)
@@ -211,8 +209,8 @@ auto SemanticsContext::ImplicitAsForArgs(
                         size_t, std::string, std::string);
       diagnostic->Note(
           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;
     }
   }
@@ -222,7 +220,7 @@ auto SemanticsContext::ImplicitAsForArgs(
 
 auto SemanticsContext::ImplicitAsRequired(ParseTree::Node parse_node,
                                           SemanticsNodeId value_id,
-                                          SemanticsNodeId as_type_id)
+                                          SemanticsTypeId as_type_id)
     -> SemanticsNodeId {
   SemanticsNodeId output_value_id = value_id;
   if (ImplicitAsImpl(value_id, as_type_id, &output_value_id) ==
@@ -234,15 +232,15 @@ auto SemanticsContext::ImplicitAsRequired(ParseTree::Node parse_node,
     emitter_
         ->Build(
             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();
   }
   return output_value_id;
 }
 
 auto SemanticsContext::ImplicitAsImpl(SemanticsNodeId value_id,
-                                      SemanticsNodeId as_type_id,
+                                      SemanticsTypeId as_type_id,
                                       SemanticsNodeId* output_value_id)
     -> ImplicitAsKind {
   // 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_type_id = value.type_id();
-  if (value_type_id == SemanticsNodeId::BuiltinInvalidType) {
+  if (value_type_id == SemanticsTypeId::InvalidType) {
     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.
     if (output_value_id != nullptr) {
       *output_value_id = SemanticsNodeId::BuiltinInvalidType;
@@ -270,7 +268,7 @@ auto SemanticsContext::ImplicitAsImpl(SemanticsNodeId value_id,
     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`.
     // Right now there is no tuple value support.
 
@@ -278,21 +276,24 @@ auto SemanticsContext::ImplicitAsImpl(SemanticsNodeId value_id,
     if (value.kind() == SemanticsNodeKind::StructValue &&
         value.GetAsStructValue() == SemanticsNodeBlockId::Empty) {
       if (output_value_id != nullptr) {
-        *output_value_id = value_type_id;
+        *output_value_id = semantics_->GetType(value_type_id);
       }
       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) {
@@ -368,11 +369,15 @@ auto SemanticsContext::ParamOrArgSave(bool for_args) -> void {
 }
 
 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

+ 8 - 8
toolchain/semantics/semantics_context.h

@@ -50,7 +50,7 @@ class SemanticsContext {
   }
 
   // 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;
 
   // 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
   // unsupported.
   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.
   // 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.
   // TODO: This should eventually return a type 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.
@@ -182,7 +182,7 @@ class SemanticsContext {
   //
   // If `output_value_id` is not null, then it will be set if there is a need to
   // cast.
-  auto ImplicitAsImpl(SemanticsNodeId value_id, SemanticsNodeId as_type_id,
+  auto ImplicitAsImpl(SemanticsNodeId value_id, SemanticsTypeId as_type_id,
                       SemanticsNodeId* output_value_id) -> ImplicitAsKind;
 
   // 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
   // SemanticsIR.
-  llvm::DenseSet<SemanticsNodeId> canonical_types_;
+  llvm::DenseMap<SemanticsNodeId, SemanticsTypeId> canonical_types_;
 };
 
 // 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 = 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()) {
     case SemanticsNodeKind::StructType: {
@@ -95,7 +96,7 @@ auto SemanticsHandleDesignatorExpression(SemanticsContext& context,
                         "Type `{0}` does not have a member `{1}`.", std::string,
                         llvm::StringRef);
       context.emitter().Emit(parse_node, DesignatorExpressionNameNotFound,
-                             context.semantics().StringifyNode(base.type_id()),
+                             context.semantics().StringifyType(base.type_id()),
                              context.semantics().GetString(name_id));
       break;
     }
@@ -104,7 +105,7 @@ auto SemanticsHandleDesignatorExpression(SemanticsContext& context,
                         "Type `{0}` does not support designator expressions.",
                         std::string);
       context.emitter().Emit(parse_node, DesignatorExpressionUnsupported,
-                             context.semantics().StringifyNode(base.type_id()));
+                             context.semantics().StringifyType(base.type_id()));
       break;
     }
   }
@@ -364,8 +365,7 @@ auto SemanticsHandlePatternBinding(SemanticsContext& context,
                                    ParseTree::Node parse_node) -> bool {
   auto [type_node, parsed_type_id] =
       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.
   auto name_node = context.node_stack().PopForSoloParseNode();
@@ -414,7 +414,7 @@ auto SemanticsHandleReturnStatement(SemanticsContext& context,
                         "Must return a {0}.", std::string);
       context.emitter()
           .Build(parse_node, ReturnStatementMissingExpression,
-                 context.semantics().StringifyNode(callable.return_type_id))
+                 context.semantics().StringifyType(callable.return_type_id))
           .Emit();
     }
 

+ 5 - 2
toolchain/semantics/semantics_handle_function.cpp

@@ -34,11 +34,14 @@ auto SemanticsHandleFunctionDefinition(SemanticsContext& context,
 auto SemanticsHandleFunctionDefinitionStart(SemanticsContext& context,
                                             ParseTree::Node parse_node)
     -> bool {
-  SemanticsNodeId return_type_id = SemanticsNodeId::Invalid;
+  SemanticsTypeId return_type_id = SemanticsTypeId::Invalid;
   if (context.parse_tree().node_kind(context.node_stack().PeekParseNode()) ==
       ParseNodeKind::ReturnType) {
     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 =
       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,
                                     ParseTree::Node parse_node) -> bool {
   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(
       ParseNodeKind::DesignatedName);
@@ -80,9 +80,7 @@ auto SemanticsHandleStructLiteral(SemanticsContext& context,
   auto refs = context.semantics().GetNodeBlock(refs_id);
   auto type_id =
       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(
       SemanticsNode::StructValue::Make(parse_node, type_id, refs_id));
@@ -117,8 +115,7 @@ auto SemanticsHandleStructTypeLiteral(SemanticsContext& context,
       << "{} is handled by StructLiteral.";
 
   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);
   return true;
 }

+ 6 - 5
toolchain/semantics/semantics_ir.cpp

@@ -24,8 +24,8 @@ auto SemanticsIR::MakeBuiltinIR() -> SemanticsIR {
   semantics.nodes_.push_back(SemanticsNode::Builtin::Make(            \
       SemanticsBuiltinKind::Name,                                     \
       SemanticsBuiltinKind::Name == SemanticsBuiltinKind::InvalidType \
-          ? SemanticsNodeId::BuiltinInvalidType                       \
-          : SemanticsNodeId::BuiltinTypeType));
+          ? SemanticsTypeId::InvalidType                              \
+          : SemanticsTypeId::TypeType));
 #include "toolchain/semantics/semantics_builtin_kind.def"
 
   CARBON_CHECK(semantics.node_blocks_.size() == 1)
@@ -141,7 +141,7 @@ auto SemanticsIR::Print(llvm::raw_ostream& out, bool include_builtins) const
   out << "]\n";
 }
 
-auto SemanticsIR::StringifyNode(SemanticsNodeId node_id) -> std::string {
+auto SemanticsIR::StringifyType(SemanticsTypeId type_id) -> std::string {
   std::string 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.
     int index = 0;
   };
-  llvm::SmallVector<Step> steps = {{.node_id = node_id}};
+  llvm::SmallVector<Step> steps = {
+      {.node_id = GetTypeAllowBuiltinTypes(type_id)}};
 
   while (!steps.empty()) {
     auto step = steps.pop_back_val();
@@ -190,7 +191,7 @@ auto SemanticsIR::StringifyNode(SemanticsNodeId node_id) -> std::string {
       }
       case SemanticsNodeKind::StructTypeField: {
         out << "." << GetString(node.GetAsStructTypeField()) << ": ";
-        steps.push_back({.node_id = node.type_id()});
+        steps.push_back({.node_id = GetTypeAllowBuiltinTypes(node.type_id())});
         break;
       }
       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.
   SemanticsNodeBlockId param_refs_id;
   // 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 {
@@ -160,11 +159,40 @@ class SemanticsIR {
     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 nodes_size() const -> int { return nodes_.size(); }
@@ -173,6 +201,10 @@ class SemanticsIR {
     return types_;
   }
 
+  auto empty_tuple_type_id() const -> SemanticsTypeId {
+    return empty_tuple_type_id_;
+  }
+
   // The node blocks, for direct mutation.
   auto node_blocks() -> llvm::SmallVector<llvm::SmallVector<SemanticsNodeId>>& {
     return node_blocks_;
@@ -217,6 +249,10 @@ class SemanticsIR {
   // by lowering.
   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,
   // at indices matching SemanticsBuiltinKind ordering.
   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.
   auto node_id = Yaml::Scalar(MatchesRegex(R"(node\+\d+)"));
   auto node_builtin = Yaml::Scalar(MatchesRegex(R"(node\w+)"));
+  auto type_id = Yaml::Scalar(MatchesRegex(R"(type\d+)"));
 
   EXPECT_THAT(
       Yaml::Value::FromText(print_output),
@@ -55,22 +56,21 @@ TEST(SemanticsIRTest, YAML) {
           Pair("real_literals", Yaml::Sequence(IsEmpty())),
           Pair("strings", Yaml::Sequence(ElementsAre("x"))),
           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.
           Pair("node_blocks",
                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.
 struct SemanticsMemberIndex : public IndexBase {
   using IndexBase::IndexBase;
@@ -160,7 +191,7 @@ class SemanticsNode {
   template <KindTemplateEnum Kind, typename... ArgTypes>
   class FactoryBase {
    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 {
       return SemanticsNode(parse_node, SemanticsNodeKind::Create(Kind), type_id,
                            arg_ids.index...);
@@ -204,7 +235,7 @@ class SemanticsNode {
    public:
     static auto Make(ParseTree::Node parse_node, ArgTypes... args) {
       return FactoryBase<Kind, ArgTypes...>::Make(
-          parse_node, SemanticsNodeId::Invalid, args...);
+          parse_node, SemanticsTypeId::Invalid, args...);
     }
     using FactoryBase<Kind, ArgTypes...>::Get;
   };
@@ -233,7 +264,7 @@ class SemanticsNode {
 
   class Builtin {
    public:
-    static auto Make(SemanticsBuiltinKind builtin_kind, SemanticsNodeId type_id)
+    static auto Make(SemanticsBuiltinKind builtin_kind, SemanticsTypeId type_id)
         -> SemanticsNode {
       // Builtins won't have a ParseTree node associated, so we provide the
       // default invalid one.
@@ -259,7 +290,7 @@ class SemanticsNode {
                            SemanticsCrossReferenceIRId /*ir_id*/,
                            SemanticsNodeId /*node_id*/> {
    public:
-    static auto Make(SemanticsNodeId type_id, SemanticsCrossReferenceIRId ir_id,
+    static auto Make(SemanticsTypeId type_id, SemanticsCrossReferenceIRId ir_id,
                      SemanticsNodeId node_id) -> SemanticsNode {
       // 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
@@ -314,7 +345,7 @@ class SemanticsNode {
 
   SemanticsNode()
       : SemanticsNode(ParseTree::Node::Invalid, SemanticsNodeKind::Invalid,
-                      SemanticsNodeId::Invalid) {}
+                      SemanticsTypeId::Invalid) {}
 
   // Provide `node.GetAsKind()` as an instance method for all kinds, essentially
   // an alias for`SemanticsNode::Kind::Get(node)`.
@@ -324,7 +355,7 @@ class SemanticsNode {
 
   auto parse_node() const -> ParseTree::Node { return parse_node_; }
   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;
 
@@ -334,7 +365,7 @@ class SemanticsNode {
   friend struct SemanticsNodeForBuiltin;
 
   explicit SemanticsNode(ParseTree::Node parse_node, SemanticsNodeKind kind,
-                         SemanticsNodeId type_id,
+                         SemanticsTypeId type_id,
                          int32_t arg0 = SemanticsNodeId::InvalidIndex,
                          int32_t arg1 = SemanticsNodeId::InvalidIndex)
       : parse_node_(parse_node),
@@ -345,7 +376,7 @@ class SemanticsNode {
 
   ParseTree::Node parse_node_;
   SemanticsNodeKind kind_;
-  SemanticsNodeId type_id_;
+  SemanticsTypeId type_id_;
 
   // Use GetAsKind to access arg0 and arg1.
   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:
       CARBON_VLOG() << entry.node_id;
       break;
+    case DebugLog::NodeBlockId:
+      CARBON_VLOG() << entry.node_block_id;
+      break;
     case DebugLog::NameId:
       CARBON_VLOG() << entry.name_id;
       break;
+    case DebugLog::TypeId:
+      CARBON_VLOG() << entry.type_id;
+      break;
   }
   CARBON_VLOG() << "\n";
   CARBON_CHECK(stack_.size() < (1 << 20))
@@ -137,6 +143,13 @@ auto SemanticsNodeStack::PopForNodeBlockId(ParseNodeKind pop_parse_kind)
   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)
     -> std::pair<ParseTree::Node, SemanticsStringId> {
   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)
       -> void {
     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.
@@ -57,6 +57,11 @@ class SemanticsNodeStack {
     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.
   auto PopAndIgnore() -> void { PopEntry(); }
 
@@ -92,6 +97,9 @@ class SemanticsNodeStack {
   // Pops the top of the stack and returns the node_block_id.
   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.
   auto PopForParseNodeAndNameId(ParseNodeKind pop_parse_kind)
       -> std::pair<ParseTree::Node, SemanticsStringId>;
@@ -121,8 +129,9 @@ class SemanticsNodeStack {
     // is used based on the ParseNodeKind.
     union {
       SemanticsNodeId node_id;
-      SemanticsStringId name_id;
       SemanticsNodeBlockId node_block_id;
+      SemanticsStringId name_id;
+      SemanticsTypeId type_id;
     };
   };
   static_assert(sizeof(Entry) == 8, "Unexpected Entry size");
@@ -131,7 +140,9 @@ class SemanticsNodeStack {
   enum DebugLog {
     None,
     NodeId,
+    NodeBlockId,
     NameId,
+    TypeId,
   };
 
   // Pushes an entry onto the stack.

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

@@ -24,18 +24,18 @@
 // CHECK:STDOUT:   nodeStringType,
 // CHECK:STDOUT: ]
 // 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: node_blocks: [
 // CHECK:STDOUT:   [

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

@@ -15,6 +15,7 @@
 // CHECK:STDOUT:   Main,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // 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: ]
 // 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: node_blocks: [
 // CHECK:STDOUT:   [

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

@@ -5,7 +5,7 @@
 // AUTOUPDATE
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // 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: ]
 // CHECK:STDOUT: integer_literals: [
@@ -20,23 +20,24 @@
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   node+0,
 // CHECK:STDOUT:   node+4,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   node+10,
 // CHECK:STDOUT: ]
 // 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: 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: 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: ]
 // CHECK:STDOUT: node_blocks: [

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

@@ -29,34 +29,35 @@
 // CHECK:STDOUT:   Main,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // CHECK:STDOUT:   {kind: FunctionDeclaration, arg0: str0, arg1: callable0},
 // 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: 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: FunctionDefinition, arg0: node+10, arg1: block0},
 // 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: ]
 // CHECK:STDOUT: node_blocks: [

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

@@ -20,16 +20,17 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   nodeFloatingPointType,
 // CHECK:STDOUT: ]
 // 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: FunctionDefinition, arg0: node+2, arg1: block0},
 // 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: ]
 // CHECK:STDOUT: node_blocks: [

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

@@ -5,7 +5,7 @@
 // AUTOUPDATE
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // 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: ]
 // CHECK:STDOUT: integer_literals: [
@@ -20,18 +20,19 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeFloatingPointType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // 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: 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: ]
 // CHECK:STDOUT: node_blocks: [

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

@@ -5,7 +5,7 @@
 // AUTOUPDATE
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // 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: ]
 // CHECK:STDOUT: integer_literals: [
@@ -21,20 +21,21 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // 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: 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: 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: ]
 // CHECK:STDOUT: node_blocks: [

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

@@ -27,29 +27,30 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // 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: FunctionDefinition, arg0: node+6, arg1: block0},
 // 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: FunctionDefinition, arg0: node+8, arg1: block4},
 // CHECK:STDOUT: ]

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

@@ -20,15 +20,16 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // 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: FunctionDefinition, arg0: node+2, arg1: block0},
 // 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: FunctionDefinition, arg0: node+4, arg1: block4},
 // CHECK:STDOUT: ]

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

@@ -21,18 +21,19 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // 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: FunctionDefinition, arg0: node+2, arg1: block0},
 // 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: 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: FunctionDefinition, arg0: node+4, arg1: block4},
 // CHECK:STDOUT: ]

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

@@ -22,19 +22,20 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // 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: FunctionDefinition, arg0: node+4, arg1: block0},
 // 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: FunctionDefinition, arg0: node+6, arg1: block4},
 // CHECK:STDOUT: ]

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

@@ -24,24 +24,25 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // 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: FunctionDefinition, arg0: node+4, arg1: block0},
 // 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: 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: FunctionDefinition, arg0: node+6, arg1: block4},
 // CHECK:STDOUT: ]

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

@@ -17,6 +17,7 @@
 // CHECK:STDOUT:   Main,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // 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: types: [
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // 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: FunctionDefinition, arg0: node+4, arg1: block0},
 // CHECK:STDOUT: ]

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

@@ -19,6 +19,7 @@
 // CHECK:STDOUT:   Baz,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // 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: types: [
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // 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: FunctionDefinition, arg0: node+2, arg1: block0},
 // CHECK:STDOUT: ]

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

@@ -17,10 +17,11 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // 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: FunctionDefinition, arg0: node+2, arg1: block0},
 // CHECK:STDOUT: ]

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

@@ -18,12 +18,13 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // 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: FunctionDefinition, arg0: node+4, arg1: block0},
 // CHECK:STDOUT: ]

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

@@ -18,12 +18,13 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // 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: FunctionDefinition, arg0: node+4, arg1: block0},
 // CHECK:STDOUT: ]

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

@@ -15,6 +15,7 @@
 // CHECK:STDOUT:   Foo,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // 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: types: [
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // 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: 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: FunctionDefinition, arg0: node+6, arg1: block0},
 // CHECK:STDOUT: ]

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

@@ -5,7 +5,7 @@
 // AUTOUPDATE
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: callables: [
-// CHECK:STDOUT:   {param_refs: block0, return_type: nodeIntegerType},
+// CHECK:STDOUT:   {param_refs: block0, return_type: type0},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: integer_literals: [
 // CHECK:STDOUT:   12,
@@ -21,10 +21,10 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // 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: ]
 // CHECK:STDOUT: node_blocks: [

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

@@ -5,7 +5,7 @@
 // AUTOUPDATE
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: callables: [
-// CHECK:STDOUT:   {param_refs: block0, return_type: nodeIntegerType},
+// CHECK:STDOUT:   {param_refs: block0, return_type: type0},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: integer_literals: [
 // CHECK:STDOUT:   12,
@@ -22,10 +22,10 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // 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: ]
 // CHECK:STDOUT: node_blocks: [

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

@@ -5,7 +5,7 @@
 // AUTOUPDATE
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: callables: [
-// CHECK:STDOUT:   {param_refs: block0, return_type: nodeIntegerType},
+// CHECK:STDOUT:   {param_refs: block0, return_type: type0},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: integer_literals: [
 // CHECK:STDOUT:   12,
@@ -23,12 +23,12 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // 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: ]
 // CHECK:STDOUT: node_blocks: [

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

@@ -5,7 +5,7 @@
 // AUTOUPDATE
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: callables: [
-// CHECK:STDOUT:   {param_refs: block0, return_type: nodeIntegerType},
+// CHECK:STDOUT:   {param_refs: block0, return_type: type0},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: integer_literals: [
 // CHECK:STDOUT: ]
@@ -21,8 +21,8 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // 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: ]
 // CHECK:STDOUT: node_blocks: [

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

@@ -16,12 +16,13 @@
 // CHECK:STDOUT:   Main,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // 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: ]
 // CHECK:STDOUT: node_blocks: [

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

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

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

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

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

@@ -5,7 +5,7 @@
 // AUTOUPDATE
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: callables: [
-// CHECK:STDOUT:   {param_refs: block0, return_type: node+1},
+// CHECK:STDOUT:   {param_refs: block0, return_type: type1},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: integer_literals: [
 // CHECK:STDOUT:   3,
@@ -22,15 +22,15 @@
 // CHECK:STDOUT:   node+6,
 // CHECK:STDOUT: ]
 // 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: 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: ]
 // CHECK:STDOUT: node_blocks: [

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

@@ -5,7 +5,7 @@
 // AUTOUPDATE
 // CHECK:STDOUT: cross_reference_irs_size: 1
 // CHECK:STDOUT: callables: [
-// CHECK:STDOUT:   {param_refs: block0, return_type: nodeIntegerType},
+// CHECK:STDOUT:   {param_refs: block0, return_type: type0},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: integer_literals: [
 // CHECK:STDOUT:   0,
@@ -20,8 +20,8 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // 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: ]
 // CHECK:STDOUT: node_blocks: [

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

@@ -20,18 +20,18 @@
 // CHECK:STDOUT:   node+7,
 // CHECK:STDOUT: ]
 // 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: node_blocks: [
 // CHECK:STDOUT:   [

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

@@ -20,13 +20,13 @@
 // CHECK:STDOUT:   node+4,
 // CHECK:STDOUT: ]
 // 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: node_blocks: [
 // CHECK:STDOUT:   [

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

@@ -21,16 +21,16 @@
 // CHECK:STDOUT:   node+7,
 // CHECK:STDOUT: ]
 // 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: node_blocks: [
 // CHECK:STDOUT:   [

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

@@ -22,16 +22,16 @@
 // CHECK:STDOUT:   node+7,
 // CHECK:STDOUT: ]
 // 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: node_blocks: [
 // CHECK:STDOUT:   [

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

@@ -23,16 +23,16 @@
 // CHECK:STDOUT:   node+7,
 // CHECK:STDOUT: ]
 // 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: node_blocks: [
 // CHECK:STDOUT:   [

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

@@ -24,19 +24,19 @@
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // 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: node_blocks: [
 // CHECK:STDOUT:   [

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

@@ -23,19 +23,19 @@
 // CHECK:STDOUT:   node+7,
 // CHECK:STDOUT: ]
 // 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: node_blocks: [
 // CHECK:STDOUT:   [

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

@@ -22,17 +22,17 @@
 // CHECK:STDOUT:   node+8,
 // CHECK:STDOUT: ]
 // 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: node_blocks: [
 // CHECK:STDOUT:   [

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

@@ -19,13 +19,13 @@
 // CHECK:STDOUT:   node+1,
 // CHECK:STDOUT: ]
 // 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: node_blocks: [
 // CHECK:STDOUT:   [

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

@@ -20,13 +20,13 @@
 // CHECK:STDOUT:   node+3,
 // CHECK:STDOUT: ]
 // 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: node_blocks: [
 // CHECK:STDOUT:   [

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

@@ -26,27 +26,27 @@
 // CHECK:STDOUT:   node+11,
 // CHECK:STDOUT: ]
 // 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: node_blocks: [
 // CHECK:STDOUT:   [

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

@@ -23,21 +23,21 @@
 // CHECK:STDOUT:   node+11,
 // CHECK:STDOUT: ]
 // 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: node_blocks: [
 // CHECK:STDOUT:   [

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

@@ -25,26 +25,26 @@
 // CHECK:STDOUT:   node+16,
 // CHECK:STDOUT: ]
 // 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: node_blocks: [
 // CHECK:STDOUT:   [

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

@@ -16,12 +16,13 @@
 // CHECK:STDOUT:   x,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // 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: ]
 // CHECK:STDOUT: node_blocks: [

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

@@ -17,14 +17,15 @@
 // CHECK:STDOUT:   x,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // 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: ]
 // CHECK:STDOUT: node_blocks: [

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

@@ -18,18 +18,19 @@
 // CHECK:STDOUT:   x,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // 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: ]
 // CHECK:STDOUT: node_blocks: [

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

@@ -17,15 +17,16 @@
 // CHECK:STDOUT:   x,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT:   nodeFloatingPointType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // 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: ]
 // CHECK:STDOUT: node_blocks: [

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

@@ -16,13 +16,14 @@
 // CHECK:STDOUT:   x,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // 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: ]
 // CHECK:STDOUT: node_blocks: [

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

@@ -17,16 +17,17 @@
 // CHECK:STDOUT:   y,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // 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: 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: node_blocks: [
 // CHECK:STDOUT:   [

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

@@ -18,15 +18,16 @@
 // CHECK:STDOUT:   x,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // 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: ]
 // CHECK:STDOUT: node_blocks: [

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

@@ -17,8 +17,8 @@
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // 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: node_blocks: [
 // CHECK:STDOUT:   [

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

@@ -18,10 +18,10 @@
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // 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: node_blocks: [
 // CHECK:STDOUT:   [

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

@@ -19,13 +19,13 @@
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // 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: node_blocks: [
 // CHECK:STDOUT:   [

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

@@ -19,16 +19,17 @@
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
 // CHECK:STDOUT:   nodeIntegerType,
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT: ]
 // 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: 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: ]
 // CHECK:STDOUT: node_blocks: [

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

@@ -17,14 +17,15 @@
 // CHECK:STDOUT:   x,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: types: [
+// CHECK:STDOUT:   nodeEmptyTupleType,
 // CHECK:STDOUT:   nodeIntegerType,
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: nodes: [
 // 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: ]
 // CHECK:STDOUT: node_blocks: [