Browse Source

Convert StructTypeField to a specific type. (#4492)

This converts `StructTypeField` from an instruction to a dedicated type,
with its own store. This had originated from discussing how
`.GetAs<SemIR::StructTypeField>` was more prevalent than for other
instructions, but is probably more interesting for the storage savings
(16 bytes StructTypeField + 4 byte LocId + 4 byte InstId -> 8 byte
StructTypeField).

Due to the different structure, these now have their own stack during
construction, reducing (but not eliminating) `args_type_info_stack_`
use-cases.

The test changes of different InstIds is expected because structs and
classes generate fewer instructions now. Other than that, results should
remain the same.

I'm generally trying to avoid unrelated cleanup here due to the PR size,
though I did scrutinize the `VerifyOnFinish` calls, adding one and
commenting others (putting them in member order because that's how I was
checking what was verified and what wasn't).
Jon Ross-Perkins 1 năm trước cách đây
mục cha
commit
be56ff87c6
48 tập tin đã thay đổi với 530 bổ sung431 xóa
  1. 3 0
      common/array_stack.h
  2. 23 22
      toolchain/check/context.cpp
  3. 13 3
      toolchain/check/context.h
  4. 11 18
      toolchain/check/convert.cpp
  5. 30 3
      toolchain/check/eval.cpp
  6. 4 7
      toolchain/check/handle_binding_pattern.cpp
  7. 24 22
      toolchain/check/handle_class.cpp
  8. 78 50
      toolchain/check/handle_struct.cpp
  9. 11 18
      toolchain/check/import_ref.cpp
  10. 0 7
      toolchain/check/inst_block_stack.h
  11. 3 4
      toolchain/check/member_access.cpp
  12. 1 1
      toolchain/check/node_stack.h
  13. 19 0
      toolchain/check/subst.cpp
  14. 4 4
      toolchain/check/testdata/alias/no_prelude/import_order.carbon
  15. 1 0
      toolchain/check/testdata/basics/builtin_insts.carbon
  16. 2 0
      toolchain/check/testdata/basics/no_prelude/multifile_raw_and_textual_ir.carbon
  17. 2 0
      toolchain/check/testdata/basics/no_prelude/multifile_raw_ir.carbon
  18. 1 0
      toolchain/check/testdata/basics/no_prelude/raw_and_textual_ir.carbon
  19. 1 0
      toolchain/check/testdata/basics/no_prelude/raw_ir.carbon
  20. 7 7
      toolchain/check/testdata/class/generic/import.carbon
  21. 9 9
      toolchain/check/testdata/class/import.carbon
  22. 4 4
      toolchain/check/testdata/class/import_base.carbon
  23. 2 2
      toolchain/check/testdata/class/import_struct_cyle.carbon
  24. 34 34
      toolchain/check/testdata/function/declaration/import.carbon
  25. 6 6
      toolchain/check/testdata/function/definition/import.carbon
  26. 1 1
      toolchain/check/testdata/interface/no_prelude/import.carbon
  27. 3 3
      toolchain/check/testdata/packages/fail_import_type_error.carbon
  28. 18 18
      toolchain/check/testdata/packages/no_prelude/cross_package_export.carbon
  29. 1 1
      toolchain/check/testdata/packages/no_prelude/export_import.carbon
  30. 23 23
      toolchain/check/testdata/packages/no_prelude/export_mixed.carbon
  31. 51 51
      toolchain/check/testdata/packages/no_prelude/export_name.carbon
  32. 26 26
      toolchain/check/testdata/return/no_prelude/import_convert_function.carbon
  33. 15 15
      toolchain/check/testdata/struct/import.carbon
  34. 0 7
      toolchain/lower/constant.cpp
  35. 3 5
      toolchain/lower/file_context.cpp
  36. 5 13
      toolchain/lower/handle_aggregates.cpp
  37. 1 0
      toolchain/sem_ir/BUILD
  38. 2 0
      toolchain/sem_ir/copy_on_write_block.h
  39. 3 1
      toolchain/sem_ir/file.cpp
  40. 10 0
      toolchain/sem_ir/file.h
  41. 2 14
      toolchain/sem_ir/formatter.cpp
  42. 3 2
      toolchain/sem_ir/id_kind.h
  43. 20 0
      toolchain/sem_ir/ids.h
  44. 0 1
      toolchain/sem_ir/inst_kind.def
  45. 9 13
      toolchain/sem_ir/stringify_type.cpp
  46. 39 0
      toolchain/sem_ir/struct_type_field.h
  47. 1 16
      toolchain/sem_ir/typed_insts.h
  48. 1 0
      toolchain/sem_ir/yaml_test.cpp

+ 3 - 0
common/array_stack.h

@@ -84,6 +84,9 @@ class ArrayStack {
   // Returns the current number of values in all arrays.
   auto all_values_size() const -> size_t { return values_.size(); }
 
+  // Returns true if the stack has no arrays pushed.
+  auto empty() const -> bool { return array_offsets_.empty(); }
+
  private:
   // For each pushed array, the start index in elements_.
   llvm::SmallVector<int32_t> array_offsets_;

+ 23 - 22
toolchain/check/context.cpp

@@ -82,10 +82,15 @@ auto Context::VerifyOnFinish() -> void {
   // various pieces of context go out of scope. At this point, nothing should
   // remain.
   // node_stack_ will still contain top-level entities.
-  scope_stack_.VerifyOnFinish();
   inst_block_stack_.VerifyOnFinish();
   pattern_block_stack_.VerifyOnFinish();
   param_and_arg_refs_stack_.VerifyOnFinish();
+  args_type_info_stack_.VerifyOnFinish();
+  CARBON_CHECK(struct_type_fields_stack_.empty());
+  // TODO: Add verification for decl_name_stack_ and
+  // decl_introducer_state_stack_.
+  scope_stack_.VerifyOnFinish();
+  // TODO: Add verification for generic_region_stack_.
 }
 
 auto Context::GetOrAddInst(SemIR::LocIdAndInst loc_id_and_inst)
@@ -847,10 +852,8 @@ class TypeCompleter {
         break;
       }
       case CARBON_KIND(SemIR::StructType inst): {
-        for (auto field_id : context_.inst_blocks().Get(inst.fields_id)) {
-          Push(context_.insts()
-                   .GetAs<SemIR::StructTypeField>(field_id)
-                   .field_type_id);
+        for (auto field : context_.struct_type_fields().Get(inst.fields_id)) {
+          Push(field.type_id);
         }
         break;
       }
@@ -981,33 +984,30 @@ class TypeCompleter {
   auto BuildValueReprForInst(SemIR::TypeId type_id,
                              SemIR::StructType struct_type) const
       -> SemIR::ValueRepr {
-    // TODO: Share more code with tuples.
-    auto fields = context_.inst_blocks().Get(struct_type.fields_id);
+    auto fields = context_.struct_type_fields().Get(struct_type.fields_id);
     if (fields.empty()) {
       return MakeEmptyValueRepr();
     }
 
     // Find the value representation for each field, and construct a struct
     // of value representations.
-    llvm::SmallVector<SemIR::InstId> value_rep_fields;
+    llvm::SmallVector<SemIR::StructTypeField> value_rep_fields;
     value_rep_fields.reserve(fields.size());
     bool same_as_object_rep = true;
-    for (auto field_id : fields) {
-      auto field = context_.insts().GetAs<SemIR::StructTypeField>(field_id);
-      auto field_value_rep = GetNestedValueRepr(field.field_type_id);
-      if (field_value_rep.type_id != field.field_type_id) {
+    for (auto field : fields) {
+      auto field_value_rep = GetNestedValueRepr(field.type_id);
+      if (field_value_rep.type_id != field.type_id) {
         same_as_object_rep = false;
-        field.field_type_id = field_value_rep.type_id;
-        field_id = context_.constant_values().GetInstId(
-            TryEvalInst(context_, SemIR::InstId::Invalid, field));
+        field.type_id = field_value_rep.type_id;
       }
-      value_rep_fields.push_back(field_id);
+      value_rep_fields.push_back(field);
     }
 
-    auto value_rep = same_as_object_rep
-                         ? type_id
-                         : context_.GetStructType(
-                               context_.inst_blocks().Add(value_rep_fields));
+    auto value_rep =
+        same_as_object_rep
+            ? type_id
+            : context_.GetStructType(
+                  context_.struct_type_fields().AddCanonical(value_rep_fields));
     return BuildStructOrTupleValueRepr(fields.size(), value_rep,
                                        same_as_object_rep);
   }
@@ -1243,8 +1243,9 @@ static auto GetCompleteTypeImpl(Context& context, EachArgT... each_arg)
   return type_id;
 }
 
-auto Context::GetStructType(SemIR::InstBlockId refs_id) -> SemIR::TypeId {
-  return GetTypeImpl<SemIR::StructType>(*this, refs_id);
+auto Context::GetStructType(SemIR::StructTypeFieldsId fields_id)
+    -> SemIR::TypeId {
+  return GetTypeImpl<SemIR::StructType>(*this, fields_id);
 }
 
 auto Context::GetTupleType(llvm::ArrayRef<SemIR::TypeId> type_ids)

+ 13 - 3
toolchain/check/context.h

@@ -394,9 +394,8 @@ class Context {
   // Returns a pointer type whose pointee type is `pointee_type_id`.
   auto GetPointerType(SemIR::TypeId pointee_type_id) -> SemIR::TypeId;
 
-  // Returns a struct type with the given fields, which should be a block of
-  // `StructTypeField`s.
-  auto GetStructType(SemIR::InstBlockId refs_id) -> SemIR::TypeId;
+  // Returns a struct type with the given fields.
+  auto GetStructType(SemIR::StructTypeFieldsId fields_id) -> SemIR::TypeId;
 
   // Returns a tuple type with the given element types.
   auto GetTupleType(llvm::ArrayRef<SemIR::TypeId> type_ids) -> SemIR::TypeId;
@@ -467,6 +466,10 @@ class Context {
     return args_type_info_stack_;
   }
 
+  auto struct_type_fields_stack() -> ArrayStack<SemIR::StructTypeField>& {
+    return struct_type_fields_stack_;
+  }
+
   auto decl_name_stack() -> DeclNameStack& { return decl_name_stack_; }
 
   auto decl_introducer_state_stack() -> DeclIntroducerStateStack& {
@@ -527,6 +530,9 @@ class Context {
   auto name_scopes() -> SemIR::NameScopeStore& {
     return sem_ir().name_scopes();
   }
+  auto struct_type_fields() -> SemIR::StructTypeFieldsStore& {
+    return sem_ir().struct_type_fields();
+  }
   auto types() -> SemIR::TypeStore& { return sem_ir().types(); }
   auto type_blocks() -> SemIR::BlockValueStore<SemIR::TypeBlockId>& {
     return sem_ir().type_blocks();
@@ -613,6 +619,10 @@ class Context {
   // arguments.
   InstBlockStack args_type_info_stack_;
 
+  // The stack of StructTypeFields for in-progress StructTypeLiterals and Class
+  // object representations.
+  ArrayStack<SemIR::StructTypeField> struct_type_fields_stack_;
+
   // The stack used for qualified declaration name construction.
   DeclNameStack decl_name_stack_;
 

+ 11 - 18
toolchain/check/convert.cpp

@@ -390,13 +390,10 @@ static auto ConvertStructToStructOrClass(Context& context,
       std::is_same_v<SemIR::ClassElementAccess, TargetAccessInstT>;
 
   auto& sem_ir = context.sem_ir();
-  auto src_elem_fields = sem_ir.inst_blocks().Get(src_type.fields_id);
-  auto dest_elem_fields = sem_ir.inst_blocks().Get(dest_type.fields_id);
-  bool dest_has_vptr =
-      !dest_elem_fields.empty() &&
-      sem_ir.insts()
-              .GetAs<SemIR::StructTypeField>(dest_elem_fields.front())
-              .name_id == SemIR::NameId::Vptr;
+  auto src_elem_fields = sem_ir.struct_type_fields().Get(src_type.fields_id);
+  auto dest_elem_fields = sem_ir.struct_type_fields().Get(dest_type.fields_id);
+  bool dest_has_vptr = !dest_elem_fields.empty() &&
+                       dest_elem_fields.front().name_id == SemIR::NameId::Vptr;
   auto dest_elem_fields_size = dest_elem_fields.size() - dest_has_vptr;
 
   auto value = sem_ir.insts().Get(value_id);
@@ -432,9 +429,8 @@ static auto ConvertStructToStructOrClass(Context& context,
   // Prepare to look up fields in the source by index.
   Map<SemIR::NameId, int32_t> src_field_indexes;
   if (src_type.fields_id != dest_type.fields_id) {
-    for (auto [i, field_id] : llvm::enumerate(src_elem_fields)) {
-      auto result = src_field_indexes.Insert(
-          context.insts().GetAs<SemIR::StructTypeField>(field_id).name_id, i);
+    for (auto [i, field] : llvm::enumerate(src_elem_fields)) {
+      auto result = src_field_indexes.Insert(field.name_id, i);
       CARBON_CHECK(result.is_inserted(), "Duplicate field in source structure");
     }
   }
@@ -460,9 +456,7 @@ static auto ConvertStructToStructOrClass(Context& context,
           : SemIR::CopyOnWriteInstBlock(
                 sem_ir, SemIR::CopyOnWriteInstBlock::UninitializedBlock{
                             dest_elem_fields.size()});
-  for (auto [i, dest_field_id] : llvm::enumerate(dest_elem_fields)) {
-    auto dest_field =
-        sem_ir.insts().GetAs<SemIR::StructTypeField>(dest_field_id);
+  for (auto [i, dest_field] : llvm::enumerate(dest_elem_fields)) {
     if (dest_field.name_id == SemIR::NameId::Vptr) {
       // TODO: Initialize the vptr to point to a vtable.
       new_block.Set(i, SemIR::InstId::BuiltinError);
@@ -494,16 +488,15 @@ static auto ConvertStructToStructOrClass(Context& context,
         return SemIR::InstId::BuiltinError;
       }
     }
-    auto src_field = sem_ir.insts().GetAs<SemIR::StructTypeField>(
-        src_elem_fields[src_field_index]);
+    auto src_field = src_elem_fields[src_field_index];
 
     // TODO: This call recurses back into conversion. Switch to an iterative
     // approach.
     auto init_id =
         ConvertAggregateElement<SemIR::StructAccess, TargetAccessInstT>(
-            context, value_loc_id, value_id, src_field.field_type_id,
-            literal_elems, inner_kind, target.init_id, dest_field.field_type_id,
-            target.init_block, src_field_index);
+            context, value_loc_id, value_id, src_field.type_id, literal_elems,
+            inner_kind, target.init_id, dest_field.type_id, target.init_block,
+            src_field_index);
     if (init_id == SemIR::InstId::BuiltinError) {
       return SemIR::InstId::BuiltinError;
     }

+ 30 - 3
toolchain/check/eval.cpp

@@ -310,6 +310,36 @@ static auto GetConstantValue(EvalContext& eval_context,
   return eval_context.inst_blocks().AddCanonical(const_insts);
 }
 
+// Compute the constant value of a type block. This may be different from the
+// input type block if we have known generic arguments.
+static auto GetConstantValue(EvalContext& eval_context,
+                             SemIR::StructTypeFieldsId fields_id, Phase* phase)
+    -> SemIR::StructTypeFieldsId {
+  if (!fields_id.is_valid()) {
+    return SemIR::StructTypeFieldsId::Invalid;
+  }
+  auto fields = eval_context.context().struct_type_fields().Get(fields_id);
+  llvm::SmallVector<SemIR::StructTypeField> new_fields;
+  for (auto field : fields) {
+    auto new_type_id = GetConstantValue(eval_context, field.type_id, phase);
+    if (!new_type_id.is_valid()) {
+      return SemIR::StructTypeFieldsId::Invalid;
+    }
+
+    // Once we leave the small buffer, we know the first few elements are all
+    // constant, so it's likely that the entire block is constant. Resize to the
+    // target size given that we're going to allocate memory now anyway.
+    if (new_fields.size() == new_fields.capacity()) {
+      new_fields.reserve(fields.size());
+    }
+
+    new_fields.push_back({.name_id = field.name_id, .type_id = new_type_id});
+  }
+  // TODO: If the new block is identical to the original block, and we know the
+  // old ID was canonical, return the original ID.
+  return eval_context.context().struct_type_fields().AddCanonical(new_fields);
+}
+
 // Compute the constant value of a type block. This may be different from the
 // input type block if we have known generic arguments.
 static auto GetConstantValue(EvalContext& eval_context,
@@ -1235,9 +1265,6 @@ static auto TryEvalInstInContext(EvalContext& eval_context,
     case SemIR::StructType::Kind:
       return RebuildIfFieldsAreConstant(eval_context, inst,
                                         &SemIR::StructType::fields_id);
-    case SemIR::StructTypeField::Kind:
-      return RebuildIfFieldsAreConstant(eval_context, inst,
-                                        &SemIR::StructTypeField::field_type_id);
     case SemIR::StructValue::Kind:
       return RebuildIfFieldsAreConstant(eval_context, inst,
                                         &SemIR::StructValue::type_id,

+ 4 - 7
toolchain/check/handle_binding_pattern.cpp

@@ -131,15 +131,12 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
             binding_id,
             {.type_id = field_type_id,
              .name_id = name_id,
-             .index = SemIR::ElementIndex(context.args_type_info_stack()
-                                              .PeekCurrentBlockContents()
-                                              .size())});
+             .index = SemIR::ElementIndex(
+                 context.struct_type_fields_stack().PeekArray().size())});
 
         // Add a corresponding field to the object representation of the class.
-        context.args_type_info_stack().AddInstId(
-            context.AddInstInNoBlock<SemIR::StructTypeField>(
-                binding_id,
-                {.name_id = name_id, .field_type_id = cast_type_id}));
+        context.struct_type_fields_stack().AppendToTop(
+            {.name_id = name_id, .type_id = cast_type_id});
         context.node_stack().Push(node_id, field_id);
         break;
       }

+ 24 - 22
toolchain/check/handle_class.cpp

@@ -295,7 +295,7 @@ auto HandleParseNode(Context& context, Parse::ClassDefinitionStartId node_id)
 
   context.inst_block_stack().Push();
   context.node_stack().Push(node_id, class_id);
-  context.args_type_info_stack().Push();
+  context.struct_type_fields_stack().PushArray();
 
   // TODO: Handle the case where there's control flow in the class body. For
   // example:
@@ -533,11 +533,10 @@ auto HandleParseNode(Context& context, Parse::BaseDeclId node_id) -> bool {
   auto field_type_id =
       context.GetUnboundElementType(class_info.self_type_id, base_info.type_id);
   class_info.base_id = context.AddInst<SemIR::BaseDecl>(
-      node_id,
-      {.type_id = field_type_id,
-       .base_type_id = base_info.type_id,
-       .index = SemIR::ElementIndex(
-           context.args_type_info_stack().PeekCurrentBlockContents().size())});
+      node_id, {.type_id = field_type_id,
+                .base_type_id = base_info.type_id,
+                .index = SemIR::ElementIndex(
+                    context.struct_type_fields_stack().PeekArray().size())});
 
   if (base_info.type_id != SemIR::TypeId::Error) {
     auto base_class_info = context.classes().Get(
@@ -548,10 +547,8 @@ auto HandleParseNode(Context& context, Parse::BaseDeclId node_id) -> bool {
   // Add a corresponding field to the object representation of the class.
   // TODO: Consider whether we want to use `partial T` here.
   // TODO: Should we diagnose if there are already any fields?
-  context.args_type_info_stack().AddInstId(
-      context.AddInstInNoBlock<SemIR::StructTypeField>(
-          node_id, {.name_id = SemIR::NameId::Base,
-                    .field_type_id = base_info.type_id}));
+  context.struct_type_fields_stack().AppendToTop(
+      {.name_id = SemIR::NameId::Base, .type_id = base_info.type_id});
 
   // Bind the name `base` in the class to the base field.
   context.decl_name_stack().AddNameOrDiagnoseDuplicate(
@@ -576,7 +573,7 @@ auto HandleParseNode(Context& context, Parse::BaseDeclId node_id) -> bool {
 static auto CheckCompleteAdapterClassType(Context& context,
                                           Parse::NodeId node_id,
                                           SemIR::ClassId class_id,
-                                          SemIR::InstBlockId fields_id)
+                                          SemIR::StructTypeFieldsId fields_id)
     -> SemIR::InstId {
   const auto& class_info = context.classes().Get(class_id);
   if (class_info.base_id.is_valid()) {
@@ -589,14 +586,17 @@ static auto CheckCompleteAdapterClassType(Context& context,
     return SemIR::InstId::BuiltinError;
   }
 
-  if (!context.inst_blocks().Get(fields_id).empty()) {
-    auto first_field_id = context.inst_blocks().Get(fields_id).front();
+  if (auto fields = context.struct_type_fields().Get(fields_id);
+      !fields.empty()) {
+    auto [first_field_inst_id, _] = context.LookupNameInExactScope(
+        node_id, fields.front().name_id, class_info.scope_id,
+        context.name_scopes().Get(class_info.scope_id));
     CARBON_DIAGNOSTIC(AdaptWithFields, Error, "adapter with fields");
     CARBON_DIAGNOSTIC(AdaptWithFieldHere, Note,
                       "first field declaration is here");
     context.emitter()
         .Build(class_info.adapt_id, AdaptWithFields)
-        .Note(first_field_id, AdaptWithFieldHere)
+        .Note(first_field_inst_id, AdaptWithFieldHere)
         .Emit();
     return SemIR::InstId::BuiltinError;
   }
@@ -649,7 +649,9 @@ static auto CheckCompleteClassType(Context& context, Parse::NodeId node_id,
                                    SemIR::ClassId class_id) -> SemIR::InstId {
   auto& class_info = context.classes().Get(class_id);
   if (class_info.adapt_id.is_valid()) {
-    auto fields_id = context.args_type_info_stack().Pop();
+    auto fields_id = context.struct_type_fields().AddCanonical(
+        context.struct_type_fields_stack().PeekArray());
+    context.struct_type_fields_stack().PopArray();
 
     return CheckCompleteAdapterClassType(context, node_id, class_id, fields_id);
   }
@@ -666,15 +668,15 @@ static auto CheckCompleteClassType(Context& context, Parse::NodeId node_id,
   }
 
   if (defining_vtable_ptr) {
-    context.args_type_info_stack().AddFrontInstId(
-        context.AddInstInNoBlock<SemIR::StructTypeField>(
-            Parse::NodeId::Invalid,
-            {.name_id = SemIR::NameId::Vptr,
-             .field_type_id = context.GetPointerType(
-                 context.GetBuiltinType(SemIR::BuiltinInstKind::VtableType))}));
+    context.struct_type_fields_stack().PrependToTop(
+        {.name_id = SemIR::NameId::Vptr,
+         .type_id = context.GetPointerType(
+             context.GetBuiltinType(SemIR::BuiltinInstKind::VtableType))});
   }
 
-  auto fields_id = context.args_type_info_stack().Pop();
+  auto fields_id = context.struct_type_fields().AddCanonical(
+      context.struct_type_fields_stack().PeekArray());
+  context.struct_type_fields_stack().PopArray();
 
   return context.AddInst<SemIR::CompleteTypeWitness>(
       node_id,

+ 78 - 50
toolchain/check/handle_struct.cpp

@@ -10,20 +10,20 @@
 
 namespace Carbon::Check {
 
-auto HandleParseNode(Context& context, Parse::StructTypeLiteralStartId node_id)
+auto HandleParseNode(Context& context, Parse::StructLiteralStartId node_id)
     -> bool {
   context.scope_stack().Push();
   context.node_stack().Push(node_id);
+  context.struct_type_fields_stack().PushArray();
   context.param_and_arg_refs_stack().Push();
   return true;
 }
 
-auto HandleParseNode(Context& context, Parse::StructLiteralStartId node_id)
+auto HandleParseNode(Context& context, Parse::StructTypeLiteralStartId node_id)
     -> bool {
   context.scope_stack().Push();
   context.node_stack().Push(node_id);
-  context.args_type_info_stack().Push();
-  context.param_and_arg_refs_stack().Push();
+  context.struct_type_fields_stack().PushArray();
   return true;
 }
 
@@ -40,52 +40,47 @@ auto HandleParseNode(Context& context, Parse::StructLiteralCommaId /*node_id*/)
   return true;
 }
 
-auto HandleParseNode(Context& context,
+auto HandleParseNode(Context& /*context*/,
                      Parse::StructTypeLiteralCommaId /*node_id*/) -> bool {
-  context.param_and_arg_refs_stack().ApplyComma();
   return true;
 }
 
 auto HandleParseNode(Context& context, Parse::StructLiteralFieldId node_id)
     -> bool {
   auto value_inst_id = context.node_stack().PopExpr();
-  auto [name_node, name_id] = context.node_stack().PopNameWithNodeId();
+  // Get the name while leaving it on the stack.
+  auto name_id = context.node_stack().Peek<Parse::NodeCategory::MemberName>();
 
   // Store the name for the type.
-  context.args_type_info_stack().AddInstId(
-      context.AddInstInNoBlock<SemIR::StructTypeField>(
-          name_node,
-          {.name_id = name_id,
-           .field_type_id = context.insts().Get(value_inst_id).type_id()}));
+  auto value_type_id = context.insts().Get(value_inst_id).type_id();
+  context.struct_type_fields_stack().AppendToTop(
+      {.name_id = name_id, .type_id = value_type_id});
 
   // Push the value back on the stack as an argument.
   context.node_stack().Push(node_id, value_inst_id);
   return true;
 }
 
-auto HandleParseNode(Context& context, Parse::StructTypeLiteralFieldId node_id)
-    -> bool {
+auto HandleParseNode(Context& context,
+                     Parse::StructTypeLiteralFieldId /*node_id*/) -> bool {
   auto [type_node, type_id] = context.node_stack().PopExprWithNodeId();
   SemIR::TypeId cast_type_id = ExprAsType(context, type_node, type_id).type_id;
+  // Get the name while leaving it on the stack.
+  auto name_id = context.node_stack().Peek<Parse::NodeCategory::MemberName>();
 
-  auto [name_node, name_id] = context.node_stack().PopNameWithNodeId();
-
-  auto inst_id = context.AddInst<SemIR::StructTypeField>(
-      name_node, {.name_id = name_id, .field_type_id = cast_type_id});
-  context.node_stack().Push(node_id, inst_id);
+  context.struct_type_fields_stack().AppendToTop(
+      {.name_id = name_id, .type_id = cast_type_id});
   return true;
 }
 
-static auto DiagnoseDuplicateNames(Context& context,
-                                   SemIR::InstBlockId type_block_id,
-                                   bool is_struct_type_literal) -> bool {
-  auto& sem_ir = context.sem_ir();
-  auto fields = sem_ir.inst_blocks().Get(type_block_id);
-  Map<SemIR::NameId, SemIR::InstId> names;
-  auto& insts = sem_ir.insts();
-  for (SemIR::InstId field_inst_id : fields) {
-    auto field_inst = insts.GetAs<SemIR::StructTypeField>(field_inst_id);
-    auto result = names.Insert(field_inst.name_id, field_inst_id);
+// Diagnoses and returns true if there's a duplicate name.
+static auto DiagnoseDuplicateNames(
+    Context& context, llvm::ArrayRef<Parse::NodeId> field_name_nodes,
+    llvm::ArrayRef<SemIR::StructTypeField> fields, bool is_struct_type_literal)
+    -> bool {
+  Map<SemIR::NameId, Parse::NodeId> names;
+  for (auto [field_name_node, field] : llvm::zip(field_name_nodes, fields)) {
+    auto result = names.Insert(field.name_id, field_name_node);
     if (!result.is_inserted()) {
       CARBON_DIAGNOSTIC(StructNameDuplicate, Error,
                         "duplicated field name `{1}` in "
@@ -94,9 +89,9 @@ static auto DiagnoseDuplicateNames(Context& context,
       CARBON_DIAGNOSTIC(StructNamePrevious, Note,
                         "field with the same name here");
       context.emitter()
-          .Build(field_inst_id, StructNameDuplicate, is_struct_type_literal,
-                 field_inst.name_id)
-          .Note(result.value(), StructNamePrevious)
+          .Build(result.value(), StructNameDuplicate, is_struct_type_literal,
+                 field.name_id)
+          .Note(field_name_node, StructNamePrevious)
           .Emit();
       return true;
     }
@@ -104,47 +99,80 @@ static auto DiagnoseDuplicateNames(Context& context,
   return false;
 }
 
+// Pops the names of each field from the stack. These will have been left while
+// handling struct fields.
+static auto PopFieldNameNodes(Context& context, size_t field_count)
+    -> llvm::SmallVector<Parse::NodeId> {
+  llvm::SmallVector<Parse::NodeId> nodes;
+  nodes.reserve(field_count);
+  while (true) {
+    auto [name_node, _] =
+        context.node_stack().PopWithNodeIdIf<Parse::NodeCategory::MemberName>();
+    if (name_node.is_valid()) {
+      nodes.push_back(name_node);
+    } else {
+      break;
+    }
+  }
+  CARBON_CHECK(nodes.size() == field_count, "Found {0} names, expected {1}",
+               nodes.size(), field_count);
+  return nodes;
+}
+
 auto HandleParseNode(Context& context, Parse::StructLiteralId node_id) -> bool {
-  auto refs_id = context.param_and_arg_refs_stack().EndAndPop(
+  if (!context.node_stack().PeekIs(Parse::NodeCategory::MemberName)) {
+    // Remove the last parameter from the node stack before collecting names.
+    context.param_and_arg_refs_stack().EndNoPop(
+        Parse::NodeKind::StructLiteralStart);
+  }
+
+  auto fields = context.struct_type_fields_stack().PeekArray();
+  llvm::SmallVector<Parse::NodeId> field_name_nodes =
+      PopFieldNameNodes(context, fields.size());
+
+  auto elements_id = context.param_and_arg_refs_stack().EndAndPop(
       Parse::NodeKind::StructLiteralStart);
 
   context.scope_stack().Pop();
   context.node_stack()
       .PopAndDiscardSoloNodeId<Parse::NodeKind::StructLiteralStart>();
-  auto type_block_id = context.args_type_info_stack().Pop();
-  if (DiagnoseDuplicateNames(context, type_block_id,
+
+  if (DiagnoseDuplicateNames(context, field_name_nodes, fields,
                              /*is_struct_type_literal=*/false)) {
     context.node_stack().Push(node_id, SemIR::InstId::BuiltinError);
-    return true;
-  }
+  } else {
+    auto type_id = context.GetStructType(
+        context.struct_type_fields().AddCanonical(fields));
 
-  auto type_id = context.GetStructType(type_block_id);
+    auto value_id = context.AddInst<SemIR::StructLiteral>(
+        node_id, {.type_id = type_id, .elements_id = elements_id});
+    context.node_stack().Push(node_id, value_id);
+  }
 
-  auto value_id = context.AddInst<SemIR::StructLiteral>(
-      node_id, {.type_id = type_id, .elements_id = refs_id});
-  context.node_stack().Push(node_id, value_id);
+  context.struct_type_fields_stack().PopArray();
   return true;
 }
 
 auto HandleParseNode(Context& context, Parse::StructTypeLiteralId node_id)
     -> bool {
-  auto refs_id = context.param_and_arg_refs_stack().EndAndPop(
-      Parse::NodeKind::StructTypeLiteralStart);
+  auto fields = context.struct_type_fields_stack().PeekArray();
+  llvm::SmallVector<Parse::NodeId> field_name_nodes =
+      PopFieldNameNodes(context, fields.size());
 
   context.scope_stack().Pop();
   context.node_stack()
       .PopAndDiscardSoloNodeId<Parse::NodeKind::StructTypeLiteralStart>();
 
-  CARBON_CHECK(refs_id != SemIR::InstBlockId::Empty,
-               "{{}} is handled by StructLiteral.");
-
-  if (DiagnoseDuplicateNames(context, refs_id,
+  if (DiagnoseDuplicateNames(context, field_name_nodes, fields,
                              /*is_struct_type_literal=*/true)) {
     context.node_stack().Push(node_id, SemIR::InstId::BuiltinError);
-    return true;
+  } else {
+    auto fields_id = context.struct_type_fields().AddCanonical(fields);
+    context.AddInstAndPush<SemIR::StructType>(
+        node_id, {.type_id = SemIR::TypeId::TypeType, .fields_id = fields_id});
   }
-  context.AddInstAndPush<SemIR::StructType>(
-      node_id, {.type_id = SemIR::TypeId::TypeType, .fields_id = refs_id});
+
+  context.struct_type_fields_stack().PopArray();
   return true;
 }
 

+ 11 - 18
toolchain/check/import_ref.cpp

@@ -1233,7 +1233,7 @@ class ImportRefResolver {
         return TryResolveTypedInst(inst);
       }
       case CARBON_KIND(SemIR::StructType inst): {
-        return TryResolveTypedInst(inst, inst_id);
+        return TryResolveTypedInst(inst);
       }
       case CARBON_KIND(SemIR::StructValue inst): {
         return TryResolveTypedInst(inst);
@@ -2147,38 +2147,31 @@ class ImportRefResolver {
                                                .specific_id = specific_id});
   }
 
-  auto TryResolveTypedInst(SemIR::StructType inst, SemIR::InstId import_inst_id)
-      -> ResolveResult {
+  auto TryResolveTypedInst(SemIR::StructType inst) -> ResolveResult {
     CARBON_CHECK(inst.type_id == SemIR::TypeId::TypeType);
-    auto orig_fields = import_ir_.inst_blocks().Get(inst.fields_id);
+    auto orig_fields = import_ir_.struct_type_fields().Get(inst.fields_id);
     llvm::SmallVector<SemIR::ConstantId> field_const_ids;
     field_const_ids.reserve(orig_fields.size());
-    for (auto field_id : orig_fields) {
-      auto field = import_ir_.insts().GetAs<SemIR::StructTypeField>(field_id);
-      field_const_ids.push_back(GetLocalConstantId(field.field_type_id));
+    for (auto field : orig_fields) {
+      field_const_ids.push_back(GetLocalConstantId(field.type_id));
     }
     if (HasNewWork()) {
       return Retry();
     }
 
     // Prepare a vector of fields for GetStructType.
-    // TODO: Should we have field constants so that we can deduplicate fields
-    // without creating instructions here?
-    llvm::SmallVector<SemIR::InstId> fields;
-    fields.reserve(orig_fields.size());
-    for (auto [field_id, field_const_id] :
+    llvm::SmallVector<SemIR::StructTypeField> new_fields;
+    new_fields.reserve(orig_fields.size());
+    for (auto [orig_field, field_const_id] :
          llvm::zip(orig_fields, field_const_ids)) {
-      auto field = import_ir_.insts().GetAs<SemIR::StructTypeField>(field_id);
-      auto name_id = GetLocalNameId(field.name_id);
+      auto name_id = GetLocalNameId(orig_field.name_id);
       auto field_type_id = context_.GetTypeIdForTypeConstant(field_const_id);
-      fields.push_back(context_.AddInstInNoBlock<SemIR::StructTypeField>(
-          AddImportIRInst(import_inst_id),
-          {.name_id = name_id, .field_type_id = field_type_id}));
+      new_fields.push_back({.name_id = name_id, .type_id = field_type_id});
     }
 
     return ResolveAs<SemIR::StructType>(
         {.type_id = SemIR::TypeId::TypeType,
-         .fields_id = context_.inst_blocks().AddCanonical(fields)});
+         .fields_id = context_.struct_type_fields().AddCanonical(new_fields)});
   }
 
   auto TryResolveTypedInst(SemIR::StructValue inst) -> ResolveResult {

+ 0 - 7
toolchain/check/inst_block_stack.h

@@ -58,13 +58,6 @@ class InstBlockStack {
     insts_stack_.AppendToTop(inst_id);
   }
 
-  // Adds the given instruction ID to the front of the block at the top of the
-  // stack.
-  auto AddFrontInstId(SemIR::InstId inst_id) -> void {
-    CARBON_CHECK(!empty(), "no current block");
-    insts_stack_.PrependToTop(inst_id);
-  }
-
   // Returns whether the current block is statically reachable.
   auto is_current_block_reachable() -> bool {
     return id_stack_.back() != SemIR::InstBlockId::Unreachable;

+ 3 - 4
toolchain/check/member_access.cpp

@@ -405,14 +405,13 @@ auto PerformMemberAccess(Context& context, SemIR::LocId loc_id,
     if (auto struct_type = context.insts().TryGetAs<SemIR::StructType>(
             context.constant_values().GetInstId(base_type_const_id))) {
       // TODO: Do we need to optimize this with a lookup table for O(1)?
-      for (auto [i, ref_id] :
-           llvm::enumerate(context.inst_blocks().Get(struct_type->fields_id))) {
-        auto field = context.insts().GetAs<SemIR::StructTypeField>(ref_id);
+      for (auto [i, field] : llvm::enumerate(
+               context.struct_type_fields().Get(struct_type->fields_id))) {
         if (name_id == field.name_id) {
           // TODO: Model this as producing a lookup result, and do instance
           // binding separately. Perhaps a struct type should be a name scope.
           return context.GetOrAddInst<SemIR::StructAccess>(
-              loc_id, {.type_id = field.field_type_id,
+              loc_id, {.type_id = field.type_id,
                        .struct_id = base_id,
                        .index = SemIR::ElementIndex(i)});
         }

+ 1 - 1
toolchain/check/node_stack.h

@@ -424,7 +424,6 @@ class NodeStack {
         case Parse::NodeKind::ShortCircuitOperandAnd:
         case Parse::NodeKind::ShortCircuitOperandOr:
         case Parse::NodeKind::StructLiteralField:
-        case Parse::NodeKind::StructTypeLiteralField:
         case Parse::NodeKind::WhereOperand:
           return Id::KindFor<SemIR::InstId>();
         case Parse::NodeKind::IfCondition:
@@ -465,6 +464,7 @@ class NodeStack {
         case Parse::NodeKind::ReturnStatementStart:
         case Parse::NodeKind::ReturnVarModifier:
         case Parse::NodeKind::StructLiteralStart:
+        case Parse::NodeKind::StructTypeLiteralField:
         case Parse::NodeKind::StructTypeLiteralStart:
         case Parse::NodeKind::TupleLiteralStart:
         case Parse::NodeKind::TuplePatternStart:

+ 19 - 0
toolchain/check/subst.cpp

@@ -77,6 +77,13 @@ static auto PushOperand(Context& context, Worklist& worklist,
         worklist.Push(inst_id);
       }
       break;
+    case SemIR::IdKind::For<SemIR::StructTypeFieldsId>: {
+      for (auto field :
+           context.struct_type_fields().Get(SemIR::StructTypeFieldsId(arg))) {
+        worklist.Push(context.types().GetInstId(field.type_id));
+      }
+      break;
+    }
     case SemIR::IdKind::For<SemIR::TypeBlockId>:
       for (auto type_id : context.type_blocks().Get(SemIR::TypeBlockId(arg))) {
         worklist.Push(context.types().GetInstId(type_id));
@@ -134,6 +141,18 @@ static auto PopOperand(Context& context, Worklist& worklist, SemIR::IdKind kind,
       }
       return new_inst_block.GetCanonical().index;
     }
+    case SemIR::IdKind::For<SemIR::StructTypeFieldsId>: {
+      SemIR::StructTypeFieldsId old_fields_id(arg);
+      auto old_fields = context.struct_type_fields().Get(old_fields_id);
+      SemIR::CopyOnWriteStructTypeFieldsBlock new_fields(context.sem_ir(),
+                                                         old_fields_id);
+      for (auto i : llvm::reverse(llvm::seq(old_fields.size()))) {
+        new_fields.Set(
+            i, {.name_id = old_fields[i].name_id,
+                .type_id = context.GetTypeIdForTypeInst(worklist.Pop())});
+      }
+      return new_fields.GetCanonical().index;
+    }
     case SemIR::IdKind::For<SemIR::TypeBlockId>: {
       SemIR::TypeBlockId old_type_block_id(arg);
       auto size = context.type_blocks().Get(old_type_block_id).size();

+ 4 - 4
toolchain/check/testdata/alias/no_prelude/import_order.carbon

@@ -85,10 +85,10 @@ var a_val: a = {.v = b_val.v};
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1 = import_ref Main//a, inst+1, unloaded
-// CHECK:STDOUT:   %import_ref.2: type = import_ref Main//a, inst+14, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.3: type = import_ref Main//a, inst+16, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.4: type = import_ref Main//a, inst+18, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.5: type = import_ref Main//a, inst+20, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.2: type = import_ref Main//a, inst+12, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.3: type = import_ref Main//a, inst+14, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.4: type = import_ref Main//a, inst+16, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.5: type = import_ref Main//a, inst+18, loaded [template = constants.%C]
 // CHECK:STDOUT:   %import_ref.6 = import_ref Main//a, inst+2, unloaded
 // CHECK:STDOUT:   %import_ref.7: %.5 = import_ref Main//a, inst+7, loaded [template = %.1]
 // CHECK:STDOUT: }

+ 1 - 0
toolchain/check/testdata/basics/builtin_insts.carbon

@@ -23,6 +23,7 @@
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:        {}
 // CHECK:STDOUT:   specifics:       {}
+// CHECK:STDOUT:   struct_type_fields: {}
 // CHECK:STDOUT:   types:
 // CHECK:STDOUT:     typeTypeType:    {kind: copy, type: typeTypeType}
 // CHECK:STDOUT:     typeError:       {kind: copy, type: typeError}

+ 2 - 0
toolchain/check/testdata/basics/no_prelude/multifile_raw_and_textual_ir.carbon

@@ -40,6 +40,7 @@ fn B() {
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:        {}
 // CHECK:STDOUT:   specifics:       {}
+// CHECK:STDOUT:   struct_type_fields: {}
 // CHECK:STDOUT:   types:
 // CHECK:STDOUT:     typeTypeType:    {kind: copy, type: typeTypeType}
 // CHECK:STDOUT:     typeError:       {kind: copy, type: typeError}
@@ -115,6 +116,7 @@ fn B() {
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:        {}
 // CHECK:STDOUT:   specifics:       {}
+// CHECK:STDOUT:   struct_type_fields: {}
 // CHECK:STDOUT:   types:
 // CHECK:STDOUT:     typeTypeType:    {kind: copy, type: typeTypeType}
 // CHECK:STDOUT:     typeError:       {kind: copy, type: typeError}

+ 2 - 0
toolchain/check/testdata/basics/no_prelude/multifile_raw_ir.carbon

@@ -40,6 +40,7 @@ fn B() {
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:        {}
 // CHECK:STDOUT:   specifics:       {}
+// CHECK:STDOUT:   struct_type_fields: {}
 // CHECK:STDOUT:   types:
 // CHECK:STDOUT:     typeTypeType:    {kind: copy, type: typeTypeType}
 // CHECK:STDOUT:     typeError:       {kind: copy, type: typeError}
@@ -94,6 +95,7 @@ fn B() {
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:        {}
 // CHECK:STDOUT:   specifics:       {}
+// CHECK:STDOUT:   struct_type_fields: {}
 // CHECK:STDOUT:   types:
 // CHECK:STDOUT:     typeTypeType:    {kind: copy, type: typeTypeType}
 // CHECK:STDOUT:     typeError:       {kind: copy, type: typeError}

+ 1 - 0
toolchain/check/testdata/basics/no_prelude/raw_and_textual_ir.carbon

@@ -31,6 +31,7 @@ fn Foo(n: ()) -> ((), ()) {
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:        {}
 // CHECK:STDOUT:   specifics:       {}
+// CHECK:STDOUT:   struct_type_fields: {}
 // CHECK:STDOUT:   types:
 // CHECK:STDOUT:     typeTypeType:    {kind: copy, type: typeTypeType}
 // CHECK:STDOUT:     typeError:       {kind: copy, type: typeError}

+ 1 - 0
toolchain/check/testdata/basics/no_prelude/raw_ir.carbon

@@ -34,6 +34,7 @@ fn Foo[T:! type](n: T) -> (T, ()) {
 // CHECK:STDOUT:     generic0:        {decl: inst+24, bindings: block11}
 // CHECK:STDOUT:   specifics:
 // CHECK:STDOUT:     specific0:       {generic: generic0, args: block13}
+// CHECK:STDOUT:   struct_type_fields: {}
 // CHECK:STDOUT:   types:
 // CHECK:STDOUT:     typeTypeType:    {kind: copy, type: typeTypeType}
 // CHECK:STDOUT:     typeError:       {kind: copy, type: typeError}

+ 7 - 7
toolchain/check/testdata/class/generic/import.carbon

@@ -275,7 +275,7 @@ class Class(U:! type) {
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1: %Class.type = import_ref Main//foo, inst+9, loaded [template = constants.%Class.1]
 // CHECK:STDOUT:   %import_ref.2: %CompleteClass.type = import_ref Main//foo, inst+21, loaded [template = constants.%CompleteClass.1]
-// CHECK:STDOUT:   %import_ref.3: %F.type.2 = import_ref Main//foo, inst+71, loaded [template = constants.%F.2]
+// CHECK:STDOUT:   %import_ref.3: %F.type.2 = import_ref Main//foo, inst+69, loaded [template = constants.%F.2]
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
 // CHECK:STDOUT:     .Int32 = %import_ref.7
 // CHECK:STDOUT:     import Core//prelude
@@ -283,7 +283,7 @@ class Class(U:! type) {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %import_ref.4 = import_ref Main//foo, inst+26, unloaded
 // CHECK:STDOUT:   %import_ref.5 = import_ref Main//foo, inst+38, unloaded
-// CHECK:STDOUT:   %import_ref.6 = import_ref Main//foo, inst+48, unloaded
+// CHECK:STDOUT:   %import_ref.6 = import_ref Main//foo, inst+46, unloaded
 // CHECK:STDOUT:   %import_ref.7: %Int32.type = import_ref Core//prelude/types, inst+15, loaded [template = constants.%Int32]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -448,7 +448,7 @@ class Class(U:! type) {
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1 = import_ref Main//foo, inst+9, unloaded
 // CHECK:STDOUT:   %import_ref.2: %CompleteClass.type = import_ref Main//foo, inst+21, loaded [template = constants.%CompleteClass.1]
-// CHECK:STDOUT:   %import_ref.3: %F.type.3 = import_ref Main//foo, inst+71, loaded [template = constants.%F.3]
+// CHECK:STDOUT:   %import_ref.3: %F.type.3 = import_ref Main//foo, inst+69, loaded [template = constants.%F.3]
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
 // CHECK:STDOUT:     .Int32 = %import_ref.4
 // CHECK:STDOUT:     import Core//prelude
@@ -457,7 +457,7 @@ class Class(U:! type) {
 // CHECK:STDOUT:   %import_ref.4: %Int32.type = import_ref Core//prelude/types, inst+15, loaded [template = constants.%Int32]
 // CHECK:STDOUT:   %import_ref.5 = import_ref Main//foo, inst+26, unloaded
 // CHECK:STDOUT:   %import_ref.6: @CompleteClass.%.1 (%.4) = import_ref Main//foo, inst+38, loaded [template = %.1]
-// CHECK:STDOUT:   %import_ref.7: @CompleteClass.%F.type (%F.type.1) = import_ref Main//foo, inst+48, loaded [symbolic = @CompleteClass.%F (constants.%F.1)]
+// CHECK:STDOUT:   %import_ref.7: @CompleteClass.%F.type (%F.type.1) = import_ref Main//foo, inst+46, loaded [symbolic = @CompleteClass.%F (constants.%F.1)]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -649,7 +649,7 @@ class Class(U:! type) {
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1 = import_ref Main//foo, inst+9, unloaded
 // CHECK:STDOUT:   %import_ref.2: %CompleteClass.type = import_ref Main//foo, inst+21, loaded [template = constants.%CompleteClass.1]
-// CHECK:STDOUT:   %import_ref.3: %F.type.3 = import_ref Main//foo, inst+71, loaded [template = constants.%F.3]
+// CHECK:STDOUT:   %import_ref.3: %F.type.3 = import_ref Main//foo, inst+69, loaded [template = constants.%F.3]
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
 // CHECK:STDOUT:     .Int32 = %import_ref.7
 // CHECK:STDOUT:     .ImplicitAs = %import_ref.8
@@ -658,7 +658,7 @@ class Class(U:! type) {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %import_ref.4 = import_ref Main//foo, inst+26, unloaded
 // CHECK:STDOUT:   %import_ref.5 = import_ref Main//foo, inst+38, unloaded
-// CHECK:STDOUT:   %import_ref.6 = import_ref Main//foo, inst+48, unloaded
+// CHECK:STDOUT:   %import_ref.6 = import_ref Main//foo, inst+46, unloaded
 // CHECK:STDOUT:   %import_ref.7: %Int32.type = import_ref Core//prelude/types, inst+15, loaded [template = constants.%Int32]
 // CHECK:STDOUT:   %import_ref.8: %ImplicitAs.type.1 = import_ref Core//prelude/operators/as, inst+49, loaded [template = constants.%ImplicitAs]
 // CHECK:STDOUT:   %import_ref.9 = import_ref Core//prelude/operators/as, inst+55, unloaded
@@ -849,7 +849,7 @@ class Class(U:! type) {
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1: %Class.type = import_ref Main//foo, inst+9, loaded [template = constants.%Class.1]
 // CHECK:STDOUT:   %import_ref.2 = import_ref Main//foo, inst+21, unloaded
-// CHECK:STDOUT:   %import_ref.3 = import_ref Main//foo, inst+71, unloaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref Main//foo, inst+69, unloaded
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
 // CHECK:STDOUT:     import Core//prelude
 // CHECK:STDOUT:     import Core//prelude/...

+ 9 - 9
toolchain/check/testdata/class/import.carbon

@@ -184,8 +184,8 @@ fn Run() {
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1: type = import_ref Main//a, inst+3, loaded [template = constants.%Empty]
 // CHECK:STDOUT:   %import_ref.2: type = import_ref Main//a, inst+8, loaded [template = constants.%Field]
-// CHECK:STDOUT:   %import_ref.3: type = import_ref Main//a, inst+28, loaded [template = constants.%ForwardDeclared.1]
-// CHECK:STDOUT:   %import_ref.4: type = import_ref Main//a, inst+51, loaded [template = constants.%Incomplete]
+// CHECK:STDOUT:   %import_ref.3: type = import_ref Main//a, inst+26, loaded [template = constants.%ForwardDeclared.1]
+// CHECK:STDOUT:   %import_ref.4: type = import_ref Main//a, inst+49, loaded [template = constants.%Incomplete]
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
 // CHECK:STDOUT:     import Core//prelude
 // CHECK:STDOUT:     import Core//prelude/...
@@ -193,12 +193,12 @@ fn Run() {
 // CHECK:STDOUT:   %import_ref.5 = import_ref Main//a, inst+4, unloaded
 // CHECK:STDOUT:   %import_ref.6 = import_ref Main//a, inst+9, unloaded
 // CHECK:STDOUT:   %import_ref.7: %.9 = import_ref Main//a, inst+22, loaded [template = %.1]
-// CHECK:STDOUT:   %import_ref.8 = import_ref Main//a, inst+29, unloaded
-// CHECK:STDOUT:   %import_ref.9: %F.type = import_ref Main//a, inst+36, loaded [template = constants.%F]
-// CHECK:STDOUT:   %import_ref.10: %G.type = import_ref Main//a, inst+47, loaded [template = constants.%G]
-// CHECK:STDOUT:   %import_ref.11 = import_ref Main//a, inst+29, unloaded
-// CHECK:STDOUT:   %import_ref.12 = import_ref Main//a, inst+36, unloaded
-// CHECK:STDOUT:   %import_ref.13 = import_ref Main//a, inst+47, unloaded
+// CHECK:STDOUT:   %import_ref.8 = import_ref Main//a, inst+27, unloaded
+// CHECK:STDOUT:   %import_ref.9: %F.type = import_ref Main//a, inst+34, loaded [template = constants.%F]
+// CHECK:STDOUT:   %import_ref.10: %G.type = import_ref Main//a, inst+45, loaded [template = constants.%G]
+// CHECK:STDOUT:   %import_ref.11 = import_ref Main//a, inst+27, unloaded
+// CHECK:STDOUT:   %import_ref.12 = import_ref Main//a, inst+34, unloaded
+// CHECK:STDOUT:   %import_ref.13 = import_ref Main//a, inst+45, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -299,5 +299,5 @@ fn Run() {
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @F[%self.param_patt: %ForwardDeclared.1]();
 // CHECK:STDOUT:
-// CHECK:STDOUT: fn @G[addr <unexpected>.inst+94: %.11]();
+// CHECK:STDOUT: fn @G[addr <unexpected>.inst+91: %.11]();
 // CHECK:STDOUT:

+ 4 - 4
toolchain/check/testdata/class/import_base.carbon

@@ -158,7 +158,7 @@ fn Run() {
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1 = import_ref Main//a, inst+3, unloaded
-// CHECK:STDOUT:   %import_ref.2: type = import_ref Main//a, inst+45, loaded [template = constants.%Child]
+// CHECK:STDOUT:   %import_ref.2: type = import_ref Main//a, inst+41, loaded [template = constants.%Child]
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
 // CHECK:STDOUT:     import Core//prelude
 // CHECK:STDOUT:     import Core//prelude/...
@@ -167,9 +167,9 @@ fn Run() {
 // CHECK:STDOUT:   %import_ref.4: %F.type = import_ref Main//a, inst+10, loaded [template = constants.%F]
 // CHECK:STDOUT:   %import_ref.5 = import_ref Main//a, inst+19, unloaded
 // CHECK:STDOUT:   %import_ref.6: %.13 = import_ref Main//a, inst+33, loaded [template = %.1]
-// CHECK:STDOUT:   %import_ref.7 = import_ref Main//a, inst+39, unloaded
-// CHECK:STDOUT:   %import_ref.8 = import_ref Main//a, inst+46, unloaded
-// CHECK:STDOUT:   %import_ref.9 = import_ref Main//a, inst+50, unloaded
+// CHECK:STDOUT:   %import_ref.7 = import_ref Main//a, inst+37, unloaded
+// CHECK:STDOUT:   %import_ref.8 = import_ref Main//a, inst+42, unloaded
+// CHECK:STDOUT:   %import_ref.9 = import_ref Main//a, inst+46, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {

+ 2 - 2
toolchain/check/testdata/class/import_struct_cyle.carbon

@@ -94,13 +94,13 @@ fn Run() {
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1 = import_ref Main//a, inst+3, unloaded
-// CHECK:STDOUT:   %import_ref.2: ref %.3 = import_ref Main//a, inst+13, loaded
+// CHECK:STDOUT:   %import_ref.2: ref %.3 = import_ref Main//a, inst+11, loaded
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
 // CHECK:STDOUT:     import Core//prelude
 // CHECK:STDOUT:     import Core//prelude/...
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %import_ref.3 = import_ref Main//a, inst+4, unloaded
-// CHECK:STDOUT:   %import_ref.4: %.7 = import_ref Main//a, inst+20, loaded [template = %.1]
+// CHECK:STDOUT:   %import_ref.4: %.7 = import_ref Main//a, inst+17, loaded [template = %.1]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {

+ 34 - 34
toolchain/check/testdata/function/declaration/import.carbon

@@ -474,13 +474,13 @@ import library "extern_api";
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1: %A.type = import_ref Main//api, inst+3, loaded [template = constants.%A]
 // CHECK:STDOUT:   %import_ref.2: %B.type = import_ref Main//api, inst+28, loaded [template = constants.%B]
-// CHECK:STDOUT:   %import_ref.3: %C.type = import_ref Main//api, inst+53, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.4: %D.type = import_ref Main//api, inst+56, loaded [template = constants.%D]
-// CHECK:STDOUT:   %import_ref.5: <namespace> = import_ref Main//api, inst+59, loaded
+// CHECK:STDOUT:   %import_ref.3: %C.type = import_ref Main//api, inst+51, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.4: %D.type = import_ref Main//api, inst+54, loaded [template = constants.%D]
+// CHECK:STDOUT:   %import_ref.5: <namespace> = import_ref Main//api, inst+57, loaded
 // CHECK:STDOUT:   %NS: <namespace> = namespace %import_ref.5, [template] {
 // CHECK:STDOUT:     .E = %import_ref.6
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.6: %E.type = import_ref Main//api, inst+60, loaded [template = constants.%E]
+// CHECK:STDOUT:   %import_ref.6: %E.type = import_ref Main//api, inst+58, loaded [template = constants.%E]
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
 // CHECK:STDOUT:     .Int32 = %import_ref.7
 // CHECK:STDOUT:     import Core//prelude
@@ -594,13 +594,13 @@ import library "extern_api";
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1: %A.type = import_ref Main//api, inst+3, loaded [template = constants.%A]
 // CHECK:STDOUT:   %import_ref.2: %B.type = import_ref Main//api, inst+28, loaded [template = constants.%B]
-// CHECK:STDOUT:   %import_ref.3: %C.type = import_ref Main//api, inst+53, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.4: %D.type = import_ref Main//api, inst+56, loaded [template = constants.%D]
-// CHECK:STDOUT:   %import_ref.5: <namespace> = import_ref Main//api, inst+59, loaded
+// CHECK:STDOUT:   %import_ref.3: %C.type = import_ref Main//api, inst+51, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.4: %D.type = import_ref Main//api, inst+54, loaded [template = constants.%D]
+// CHECK:STDOUT:   %import_ref.5: <namespace> = import_ref Main//api, inst+57, loaded
 // CHECK:STDOUT:   %NS: <namespace> = namespace %import_ref.5, [template] {
 // CHECK:STDOUT:     .E = file.%E.decl
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.6: %E.type = import_ref Main//api, inst+60, loaded [template = constants.%E]
+// CHECK:STDOUT:   %import_ref.6: %E.type = import_ref Main//api, inst+58, loaded [template = constants.%E]
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
 // CHECK:STDOUT:     .Int32 = %import_ref.7
 // CHECK:STDOUT:     import Core//prelude
@@ -744,13 +744,13 @@ import library "extern_api";
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1: %A.type = import_ref Main//extern_api, inst+3, loaded [template = constants.%A]
 // CHECK:STDOUT:   %import_ref.2: %B.type = import_ref Main//extern_api, inst+28, loaded [template = constants.%B]
-// CHECK:STDOUT:   %import_ref.3: %C.type = import_ref Main//extern_api, inst+53, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.4: %D.type = import_ref Main//extern_api, inst+56, loaded [template = constants.%D]
-// CHECK:STDOUT:   %import_ref.5: <namespace> = import_ref Main//extern_api, inst+59, loaded
+// CHECK:STDOUT:   %import_ref.3: %C.type = import_ref Main//extern_api, inst+51, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.4: %D.type = import_ref Main//extern_api, inst+54, loaded [template = constants.%D]
+// CHECK:STDOUT:   %import_ref.5: <namespace> = import_ref Main//extern_api, inst+57, loaded
 // CHECK:STDOUT:   %NS: <namespace> = namespace %import_ref.5, [template] {
 // CHECK:STDOUT:     .E = file.%E.decl
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.6: %E.type = import_ref Main//extern_api, inst+60, loaded [template = constants.%E]
+// CHECK:STDOUT:   %import_ref.6: %E.type = import_ref Main//extern_api, inst+58, loaded [template = constants.%E]
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
 // CHECK:STDOUT:     .Int32 = %import_ref.7
 // CHECK:STDOUT:     import Core//prelude
@@ -893,18 +893,18 @@ import library "extern_api";
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1: %A.type = import_ref Main//api, inst+3, loaded [template = constants.%A]
 // CHECK:STDOUT:   %import_ref.2: %B.type = import_ref Main//api, inst+28, loaded [template = constants.%B]
-// CHECK:STDOUT:   %import_ref.3: %C.type = import_ref Main//api, inst+53, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.4: %D.type = import_ref Main//api, inst+56, loaded [template = constants.%D]
-// CHECK:STDOUT:   %import_ref.5: <namespace> = import_ref Main//api, inst+59, loaded
+// CHECK:STDOUT:   %import_ref.3: %C.type = import_ref Main//api, inst+51, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.4: %D.type = import_ref Main//api, inst+54, loaded [template = constants.%D]
+// CHECK:STDOUT:   %import_ref.5: <namespace> = import_ref Main//api, inst+57, loaded
 // CHECK:STDOUT:   %NS: <namespace> = namespace %import_ref.5, [template] {
 // CHECK:STDOUT:     .E = %import_ref.6
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.6: %E.type = import_ref Main//api, inst+60, loaded [template = constants.%E]
+// CHECK:STDOUT:   %import_ref.6: %E.type = import_ref Main//api, inst+58, loaded [template = constants.%E]
 // CHECK:STDOUT:   %import_ref.7 = import_ref Main//extern_api, inst+3, unloaded
 // CHECK:STDOUT:   %import_ref.8 = import_ref Main//extern_api, inst+28, unloaded
-// CHECK:STDOUT:   %import_ref.9 = import_ref Main//extern_api, inst+53, unloaded
-// CHECK:STDOUT:   %import_ref.10 = import_ref Main//extern_api, inst+56, unloaded
-// CHECK:STDOUT:   %import_ref.11 = import_ref Main//extern_api, inst+60, unloaded
+// CHECK:STDOUT:   %import_ref.9 = import_ref Main//extern_api, inst+51, unloaded
+// CHECK:STDOUT:   %import_ref.10 = import_ref Main//extern_api, inst+54, unloaded
+// CHECK:STDOUT:   %import_ref.11 = import_ref Main//extern_api, inst+58, unloaded
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
 // CHECK:STDOUT:     .Int32 = %import_ref.12
 // CHECK:STDOUT:     import Core//prelude
@@ -1017,18 +1017,18 @@ import library "extern_api";
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1: %A.type = import_ref Main//extern_api, inst+3, loaded [template = constants.%A]
 // CHECK:STDOUT:   %import_ref.2: %B.type = import_ref Main//extern_api, inst+28, loaded [template = constants.%B]
-// CHECK:STDOUT:   %import_ref.3: %C.type = import_ref Main//extern_api, inst+53, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.4: %D.type = import_ref Main//extern_api, inst+56, loaded [template = constants.%D]
-// CHECK:STDOUT:   %import_ref.5: <namespace> = import_ref Main//extern_api, inst+59, loaded
+// CHECK:STDOUT:   %import_ref.3: %C.type = import_ref Main//extern_api, inst+51, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.4: %D.type = import_ref Main//extern_api, inst+54, loaded [template = constants.%D]
+// CHECK:STDOUT:   %import_ref.5: <namespace> = import_ref Main//extern_api, inst+57, loaded
 // CHECK:STDOUT:   %NS: <namespace> = namespace %import_ref.5, [template] {
 // CHECK:STDOUT:     .E = %import_ref.6
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.6: %E.type = import_ref Main//extern_api, inst+60, loaded [template = constants.%E]
+// CHECK:STDOUT:   %import_ref.6: %E.type = import_ref Main//extern_api, inst+58, loaded [template = constants.%E]
 // CHECK:STDOUT:   %import_ref.7 = import_ref Main//api, inst+3, unloaded
 // CHECK:STDOUT:   %import_ref.8 = import_ref Main//api, inst+28, unloaded
-// CHECK:STDOUT:   %import_ref.9 = import_ref Main//api, inst+53, unloaded
-// CHECK:STDOUT:   %import_ref.10 = import_ref Main//api, inst+56, unloaded
-// CHECK:STDOUT:   %import_ref.11 = import_ref Main//api, inst+60, unloaded
+// CHECK:STDOUT:   %import_ref.9 = import_ref Main//api, inst+51, unloaded
+// CHECK:STDOUT:   %import_ref.10 = import_ref Main//api, inst+54, unloaded
+// CHECK:STDOUT:   %import_ref.11 = import_ref Main//api, inst+58, unloaded
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
 // CHECK:STDOUT:     .Int32 = %import_ref.12
 // CHECK:STDOUT:     import Core//prelude
@@ -1121,13 +1121,13 @@ import library "extern_api";
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1 = import_ref Main//api, inst+3, unloaded
 // CHECK:STDOUT:   %import_ref.2 = import_ref Main//api, inst+28, unloaded
-// CHECK:STDOUT:   %import_ref.3 = import_ref Main//api, inst+53, unloaded
-// CHECK:STDOUT:   %import_ref.4 = import_ref Main//api, inst+56, unloaded
-// CHECK:STDOUT:   %import_ref.5: <namespace> = import_ref Main//api, inst+59, loaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref Main//api, inst+51, unloaded
+// CHECK:STDOUT:   %import_ref.4 = import_ref Main//api, inst+54, unloaded
+// CHECK:STDOUT:   %import_ref.5: <namespace> = import_ref Main//api, inst+57, loaded
 // CHECK:STDOUT:   %NS: <namespace> = namespace %import_ref.5, [template] {
 // CHECK:STDOUT:     .E = %import_ref.6
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.6 = import_ref Main//api, inst+60, unloaded
+// CHECK:STDOUT:   %import_ref.6 = import_ref Main//api, inst+58, unloaded
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
 // CHECK:STDOUT:     import Core//prelude
 // CHECK:STDOUT:     import Core//prelude/...
@@ -1152,13 +1152,13 @@ import library "extern_api";
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1 = import_ref Main//extern_api, inst+3, unloaded
 // CHECK:STDOUT:   %import_ref.2 = import_ref Main//extern_api, inst+28, unloaded
-// CHECK:STDOUT:   %import_ref.3 = import_ref Main//extern_api, inst+53, unloaded
-// CHECK:STDOUT:   %import_ref.4 = import_ref Main//extern_api, inst+56, unloaded
-// CHECK:STDOUT:   %import_ref.5: <namespace> = import_ref Main//extern_api, inst+59, loaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref Main//extern_api, inst+51, unloaded
+// CHECK:STDOUT:   %import_ref.4 = import_ref Main//extern_api, inst+54, unloaded
+// CHECK:STDOUT:   %import_ref.5: <namespace> = import_ref Main//extern_api, inst+57, loaded
 // CHECK:STDOUT:   %NS: <namespace> = namespace %import_ref.5, [template] {
 // CHECK:STDOUT:     .E = %import_ref.6
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.6 = import_ref Main//extern_api, inst+60, unloaded
+// CHECK:STDOUT:   %import_ref.6 = import_ref Main//extern_api, inst+58, unloaded
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
 // CHECK:STDOUT:     import Core//prelude
 // CHECK:STDOUT:     import Core//prelude/...

+ 6 - 6
toolchain/check/testdata/function/definition/import.carbon

@@ -261,8 +261,8 @@ fn D() {}
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1: %A.type = import_ref Main//fns, inst+3, loaded [template = constants.%A]
 // CHECK:STDOUT:   %import_ref.2: %B.type = import_ref Main//fns, inst+29, loaded [template = constants.%B]
-// CHECK:STDOUT:   %import_ref.3: %C.type = import_ref Main//fns, inst+56, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.4 = import_ref Main//fns, inst+68, unloaded
+// CHECK:STDOUT:   %import_ref.3: %C.type = import_ref Main//fns, inst+54, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.4 = import_ref Main//fns, inst+65, unloaded
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
 // CHECK:STDOUT:     .Int32 = %import_ref.5
 // CHECK:STDOUT:     import Core//prelude
@@ -343,8 +343,8 @@ fn D() {}
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1: %A.type = import_ref Main//fns, inst+3, loaded [template = constants.%A]
 // CHECK:STDOUT:   %import_ref.2: %B.type = import_ref Main//fns, inst+29, loaded [template = constants.%B]
-// CHECK:STDOUT:   %import_ref.3 = import_ref Main//fns, inst+56, unloaded
-// CHECK:STDOUT:   %import_ref.4 = import_ref Main//fns, inst+68, unloaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref Main//fns, inst+54, unloaded
+// CHECK:STDOUT:   %import_ref.4 = import_ref Main//fns, inst+65, unloaded
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
 // CHECK:STDOUT:     .Int32 = %import_ref.5
 // CHECK:STDOUT:     import Core//prelude
@@ -430,8 +430,8 @@ fn D() {}
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1 = import_ref Main//fns, inst+3, unloaded
 // CHECK:STDOUT:   %import_ref.2 = import_ref Main//fns, inst+29, unloaded
-// CHECK:STDOUT:   %import_ref.3 = import_ref Main//fns, inst+56, unloaded
-// CHECK:STDOUT:   %import_ref.4: %D.type = import_ref Main//fns, inst+68, loaded [template = constants.%D]
+// CHECK:STDOUT:   %import_ref.3 = import_ref Main//fns, inst+54, unloaded
+// CHECK:STDOUT:   %import_ref.4: %D.type = import_ref Main//fns, inst+65, loaded [template = constants.%D]
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
 // CHECK:STDOUT:     import Core//prelude
 // CHECK:STDOUT:     import Core//prelude/...

+ 1 - 1
toolchain/check/testdata/interface/no_prelude/import.carbon

@@ -177,7 +177,7 @@ var f: ForwardDeclared* = &f_ref.f;
 // CHECK:STDOUT:   %import_ref.1: type = import_ref Main//a, inst+1, loaded [template = constants.%Empty.type]
 // CHECK:STDOUT:   %import_ref.2: type = import_ref Main//a, inst+5, loaded [template = constants.%Basic.type]
 // CHECK:STDOUT:   %import_ref.3: type = import_ref Main//a, inst+20, loaded [template = constants.%ForwardDeclared.type]
-// CHECK:STDOUT:   %import_ref.4: ref %.11 = import_ref Main//a, inst+42, loaded
+// CHECK:STDOUT:   %import_ref.4: ref %.11 = import_ref Main//a, inst+39, loaded
 // CHECK:STDOUT:   %import_ref.5 = import_ref Main//a, inst+3, unloaded
 // CHECK:STDOUT:   %import_ref.6 = import_ref Main//a, inst+7, unloaded
 // CHECK:STDOUT:   %import_ref.7: %.2 = import_ref Main//a, inst+11, loaded [template = constants.%.3]

+ 3 - 3
toolchain/check/testdata/packages/fail_import_type_error.carbon

@@ -88,9 +88,9 @@ var d: i32 = d_ref;
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1: ref <error> = import_ref Implicit//default, inst+5, loaded
-// CHECK:STDOUT:   %import_ref.2: ref <error> = import_ref Implicit//default, inst+10, loaded
-// CHECK:STDOUT:   %import_ref.3: ref <error> = import_ref Implicit//default, inst+14, loaded
-// CHECK:STDOUT:   %import_ref.4: ref <error> = import_ref Implicit//default, inst+18, loaded
+// CHECK:STDOUT:   %import_ref.2: ref <error> = import_ref Implicit//default, inst+9, loaded
+// CHECK:STDOUT:   %import_ref.3: ref <error> = import_ref Implicit//default, inst+13, loaded
+// CHECK:STDOUT:   %import_ref.4: ref <error> = import_ref Implicit//default, inst+17, loaded
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
 // CHECK:STDOUT:     .Int32 = %import_ref.5
 // CHECK:STDOUT:     import Core//prelude

+ 18 - 18
toolchain/check/testdata/packages/no_prelude/cross_package_export.carbon

@@ -346,9 +346,9 @@ alias C = Other.C;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref.1: type = import_ref Other//export_name, inst+12, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.2 = import_ref Other//export_name, inst+10, unloaded
-// CHECK:STDOUT:   %import_ref.3 = import_ref Other//export_name, inst+11, unloaded
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Other//export_name, inst+10, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.2 = import_ref Other//export_name, inst+8, unloaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref Other//export_name, inst+9, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -546,9 +546,9 @@ alias C = Other.C;
 // CHECK:STDOUT:     .C = %import_ref.1
 // CHECK:STDOUT:     import Other//export_name
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.1: type = import_ref Other//export_name, inst+12, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.2 = import_ref Other//export_name, inst+10, unloaded
-// CHECK:STDOUT:   %import_ref.3 = import_ref Other//export_name, inst+11, unloaded
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Other//export_name, inst+10, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.2 = import_ref Other//export_name, inst+8, unloaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref Other//export_name, inst+9, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -600,9 +600,9 @@ alias C = Other.C;
 // CHECK:STDOUT:     import Other//export_name
 // CHECK:STDOUT:     import Other//export_name_copy
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.1: type = import_ref Other//export_name, inst+12, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.2 = import_ref Other//export_name, inst+10, unloaded
-// CHECK:STDOUT:   %import_ref.3 = import_ref Other//export_name, inst+11, unloaded
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Other//export_name, inst+10, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.2 = import_ref Other//export_name, inst+8, unloaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref Other//export_name, inst+9, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -653,9 +653,9 @@ alias C = Other.C;
 // CHECK:STDOUT:     .C = %import_ref.1
 // CHECK:STDOUT:     import Other//export_name_indirect
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.1: type = import_ref Other//export_name_indirect, inst+12, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.2 = import_ref Other//export_name_indirect, inst+10, unloaded
-// CHECK:STDOUT:   %import_ref.3 = import_ref Other//export_name_indirect, inst+11, unloaded
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Other//export_name_indirect, inst+10, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.2 = import_ref Other//export_name_indirect, inst+8, unloaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref Other//export_name_indirect, inst+9, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -712,9 +712,9 @@ alias C = Other.C;
 // CHECK:STDOUT:     import Other//export_name_indirect
 // CHECK:STDOUT:     import Other//base
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.1: type = import_ref Other//export_name, inst+12, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.2 = import_ref Other//export_name, inst+10, unloaded
-// CHECK:STDOUT:   %import_ref.3 = import_ref Other//export_name, inst+11, unloaded
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Other//export_name, inst+10, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.2 = import_ref Other//export_name, inst+8, unloaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref Other//export_name, inst+9, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -828,9 +828,9 @@ alias C = Other.C;
 // CHECK:STDOUT:     import Other//export_name
 // CHECK:STDOUT:     import Other//conflict
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.1: type = import_ref Other//export_name, inst+12, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.2 = import_ref Other//export_name, inst+10, unloaded
-// CHECK:STDOUT:   %import_ref.3 = import_ref Other//export_name, inst+11, unloaded
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Other//export_name, inst+10, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.2 = import_ref Other//export_name, inst+8, unloaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref Other//export_name, inst+9, unloaded
 // CHECK:STDOUT:   %import_ref.4 = import_ref Other//conflict, inst+1, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 1 - 1
toolchain/check/testdata/packages/no_prelude/export_import.carbon

@@ -771,7 +771,7 @@ var indirect_c: C = {.x = ()};
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref.1 = import_ref Main//use_non_export_then_base, inst+15, unloaded
+// CHECK:STDOUT:   %import_ref.1 = import_ref Main//use_non_export_then_base, inst+13, unloaded
 // CHECK:STDOUT:   %import_ref.2: type = import_ref Main//base, inst+1, loaded [template = constants.%C]
 // CHECK:STDOUT:   %import_ref.3 = import_ref Main//base, inst+2, unloaded
 // CHECK:STDOUT:   %import_ref.4 = import_ref Main//base, inst+7, unloaded

+ 23 - 23
toolchain/check/testdata/packages/no_prelude/export_mixed.carbon

@@ -162,7 +162,7 @@ var d: D = {.y = ()};
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1 = import_ref Main//base, inst+1, unloaded
-// CHECK:STDOUT:   %import_ref.2 = import_ref Main//base, inst+13, unloaded
+// CHECK:STDOUT:   %import_ref.2 = import_ref Main//base, inst+11, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -184,7 +184,7 @@ var d: D = {.y = ()};
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1: type = import_ref Main//base, inst+1, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.2 = import_ref Main//base, inst+13, unloaded
+// CHECK:STDOUT:   %import_ref.2 = import_ref Main//base, inst+11, unloaded
 // CHECK:STDOUT:   %import_ref.3 = import_ref Main//base, inst+2, unloaded
 // CHECK:STDOUT:   %import_ref.4 = import_ref Main//base, inst+7, unloaded
 // CHECK:STDOUT: }
@@ -215,7 +215,7 @@ var d: D = {.y = ()};
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1: type = import_ref Main//base, inst+1, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.2 = import_ref Main//base, inst+13, unloaded
+// CHECK:STDOUT:   %import_ref.2 = import_ref Main//base, inst+11, unloaded
 // CHECK:STDOUT:   %import_ref.3 = import_ref Main//base, inst+2, unloaded
 // CHECK:STDOUT:   %import_ref.4 = import_ref Main//base, inst+7, unloaded
 // CHECK:STDOUT: }
@@ -238,7 +238,7 @@ var d: D = {.y = ()};
 // CHECK:STDOUT: --- export_name_then_import.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref = import_ref Main//export_name, inst+13, unloaded
+// CHECK:STDOUT:   %import_ref = import_ref Main//export_name, inst+11, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -261,9 +261,9 @@ var d: D = {.y = ()};
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//export_import_then_name, inst+13, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.2 = import_ref Main//export_import_then_name, inst+11, unloaded
-// CHECK:STDOUT:   %import_ref.3 = import_ref Main//export_import_then_name, inst+12, unloaded
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//export_import_then_name, inst+11, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.2 = import_ref Main//export_import_then_name, inst+9, unloaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref Main//export_import_then_name, inst+10, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -309,9 +309,9 @@ var d: D = {.y = ()};
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//export_name, inst+13, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.2 = import_ref Main//export_name, inst+11, unloaded
-// CHECK:STDOUT:   %import_ref.3 = import_ref Main//export_name, inst+12, unloaded
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//export_name, inst+11, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.2 = import_ref Main//export_name, inst+9, unloaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref Main//export_name, inst+10, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -357,9 +357,9 @@ var d: D = {.y = ()};
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//export_import_then_name, inst+13, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.2 = import_ref Main//export_import_then_name, inst+11, unloaded
-// CHECK:STDOUT:   %import_ref.3 = import_ref Main//export_import_then_name, inst+12, unloaded
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//export_import_then_name, inst+11, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.2 = import_ref Main//export_import_then_name, inst+9, unloaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref Main//export_import_then_name, inst+10, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -400,7 +400,7 @@ var d: D = {.y = ()};
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref = import_ref Main//export_import_then_name, inst+13, unloaded
+// CHECK:STDOUT:   %import_ref = import_ref Main//export_import_then_name, inst+11, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -435,9 +435,9 @@ var d: D = {.y = ()};
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//export_import_then_name, inst+13, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.2 = import_ref Main//export_import_then_name, inst+11, unloaded
-// CHECK:STDOUT:   %import_ref.3 = import_ref Main//export_import_then_name, inst+12, unloaded
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//export_import_then_name, inst+11, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.2 = import_ref Main//export_import_then_name, inst+9, unloaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref Main//export_import_then_name, inst+10, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -488,12 +488,12 @@ var d: D = {.y = ()};
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//export_import_then_name, inst+13, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.2: type = import_ref Main//base, inst+13, loaded [template = constants.%D]
-// CHECK:STDOUT:   %import_ref.3 = import_ref Main//export_import_then_name, inst+11, unloaded
-// CHECK:STDOUT:   %import_ref.4 = import_ref Main//export_import_then_name, inst+12, unloaded
-// CHECK:STDOUT:   %import_ref.5 = import_ref Main//base, inst+14, unloaded
-// CHECK:STDOUT:   %import_ref.6 = import_ref Main//base, inst+18, unloaded
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//export_import_then_name, inst+11, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.2: type = import_ref Main//base, inst+11, loaded [template = constants.%D]
+// CHECK:STDOUT:   %import_ref.3 = import_ref Main//export_import_then_name, inst+9, unloaded
+// CHECK:STDOUT:   %import_ref.4 = import_ref Main//export_import_then_name, inst+10, unloaded
+// CHECK:STDOUT:   %import_ref.5 = import_ref Main//base, inst+12, unloaded
+// CHECK:STDOUT:   %import_ref.6 = import_ref Main//base, inst+16, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {

+ 51 - 51
toolchain/check/testdata/packages/no_prelude/export_name.carbon

@@ -262,15 +262,15 @@ private export C;
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1: type = import_ref Main//base, inst+1, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.2: <namespace> = import_ref Main//base, inst+13, loaded
+// CHECK:STDOUT:   %import_ref.2: <namespace> = import_ref Main//base, inst+11, loaded
 // CHECK:STDOUT:   %NS: <namespace> = namespace %import_ref.2, [template] {
 // CHECK:STDOUT:     .NSC = file.%NSC
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.3: type = import_ref Main//base, inst+14, loaded [template = constants.%NSC]
+// CHECK:STDOUT:   %import_ref.3: type = import_ref Main//base, inst+12, loaded [template = constants.%NSC]
 // CHECK:STDOUT:   %import_ref.4 = import_ref Main//base, inst+2, unloaded
 // CHECK:STDOUT:   %import_ref.5 = import_ref Main//base, inst+7, unloaded
-// CHECK:STDOUT:   %import_ref.6 = import_ref Main//base, inst+15, unloaded
-// CHECK:STDOUT:   %import_ref.7 = import_ref Main//base, inst+19, unloaded
+// CHECK:STDOUT:   %import_ref.6 = import_ref Main//base, inst+13, unloaded
+// CHECK:STDOUT:   %import_ref.7 = import_ref Main//base, inst+17, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -298,12 +298,12 @@ private export C;
 // CHECK:STDOUT: --- not_reexporting.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref.1 = import_ref Main//export, inst+15, unloaded
+// CHECK:STDOUT:   %import_ref.1 = import_ref Main//export, inst+13, unloaded
 // CHECK:STDOUT:   %import_ref.2: <namespace> = import_ref Main//export, inst+4, loaded
 // CHECK:STDOUT:   %NS: <namespace> = namespace %import_ref.2, [template] {
 // CHECK:STDOUT:     .NSC = %import_ref.3
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.3 = import_ref Main//export, inst+24, unloaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref Main//export, inst+20, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -327,16 +327,16 @@ private export C;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//export, inst+15, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//export, inst+13, loaded [template = constants.%C]
 // CHECK:STDOUT:   %import_ref.2: <namespace> = import_ref Main//export, inst+4, loaded
 // CHECK:STDOUT:   %NS: <namespace> = namespace %import_ref.2, [template] {
 // CHECK:STDOUT:     .NSC = file.%NSC
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.3: type = import_ref Main//export, inst+24, loaded [template = constants.%NSC]
-// CHECK:STDOUT:   %import_ref.4 = import_ref Main//export, inst+13, unloaded
-// CHECK:STDOUT:   %import_ref.5 = import_ref Main//export, inst+14, unloaded
-// CHECK:STDOUT:   %import_ref.6 = import_ref Main//export, inst+22, unloaded
-// CHECK:STDOUT:   %import_ref.7 = import_ref Main//export, inst+23, unloaded
+// CHECK:STDOUT:   %import_ref.3: type = import_ref Main//export, inst+20, loaded [template = constants.%NSC]
+// CHECK:STDOUT:   %import_ref.4 = import_ref Main//export, inst+11, unloaded
+// CHECK:STDOUT:   %import_ref.5 = import_ref Main//export, inst+12, unloaded
+// CHECK:STDOUT:   %import_ref.6 = import_ref Main//export, inst+18, unloaded
+// CHECK:STDOUT:   %import_ref.7 = import_ref Main//export, inst+19, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -385,16 +385,16 @@ private export C;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//export, inst+15, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//export, inst+13, loaded [template = constants.%C]
 // CHECK:STDOUT:   %import_ref.2: <namespace> = import_ref Main//export, inst+4, loaded
 // CHECK:STDOUT:   %NS: <namespace> = namespace %import_ref.2, [template] {
 // CHECK:STDOUT:     .NSC = %import_ref.3
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.3: type = import_ref Main//export, inst+24, loaded [template = constants.%NSC]
-// CHECK:STDOUT:   %import_ref.4 = import_ref Main//export, inst+13, unloaded
-// CHECK:STDOUT:   %import_ref.5 = import_ref Main//export, inst+14, unloaded
-// CHECK:STDOUT:   %import_ref.6 = import_ref Main//export, inst+22, unloaded
-// CHECK:STDOUT:   %import_ref.7 = import_ref Main//export, inst+23, unloaded
+// CHECK:STDOUT:   %import_ref.3: type = import_ref Main//export, inst+20, loaded [template = constants.%NSC]
+// CHECK:STDOUT:   %import_ref.4 = import_ref Main//export, inst+11, unloaded
+// CHECK:STDOUT:   %import_ref.5 = import_ref Main//export, inst+12, unloaded
+// CHECK:STDOUT:   %import_ref.6 = import_ref Main//export, inst+18, unloaded
+// CHECK:STDOUT:   %import_ref.7 = import_ref Main//export, inst+19, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -465,16 +465,16 @@ private export C;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//export_export, inst+15, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//export_export, inst+13, loaded [template = constants.%C]
 // CHECK:STDOUT:   %import_ref.2: <namespace> = import_ref Main//export_export, inst+4, loaded
 // CHECK:STDOUT:   %NS: <namespace> = namespace %import_ref.2, [template] {
 // CHECK:STDOUT:     .NSC = %import_ref.3
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.3: type = import_ref Main//export_export, inst+24, loaded [template = constants.%NSC]
-// CHECK:STDOUT:   %import_ref.4 = import_ref Main//export_export, inst+13, unloaded
-// CHECK:STDOUT:   %import_ref.5 = import_ref Main//export_export, inst+14, unloaded
-// CHECK:STDOUT:   %import_ref.6 = import_ref Main//export_export, inst+22, unloaded
-// CHECK:STDOUT:   %import_ref.7 = import_ref Main//export_export, inst+23, unloaded
+// CHECK:STDOUT:   %import_ref.3: type = import_ref Main//export_export, inst+20, loaded [template = constants.%NSC]
+// CHECK:STDOUT:   %import_ref.4 = import_ref Main//export_export, inst+11, unloaded
+// CHECK:STDOUT:   %import_ref.5 = import_ref Main//export_export, inst+12, unloaded
+// CHECK:STDOUT:   %import_ref.6 = import_ref Main//export_export, inst+18, unloaded
+// CHECK:STDOUT:   %import_ref.7 = import_ref Main//export_export, inst+19, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -546,16 +546,16 @@ private export C;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//export_export, inst+15, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//export_export, inst+13, loaded [template = constants.%C]
 // CHECK:STDOUT:   %import_ref.2: <namespace> = import_ref Main//export_export, inst+4, loaded
 // CHECK:STDOUT:   %NS: <namespace> = namespace %import_ref.2, [template] {
 // CHECK:STDOUT:     .NSC = %import_ref.3
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.3: type = import_ref Main//export_export, inst+24, loaded [template = constants.%NSC]
-// CHECK:STDOUT:   %import_ref.4 = import_ref Main//export_export, inst+13, unloaded
-// CHECK:STDOUT:   %import_ref.5 = import_ref Main//export_export, inst+14, unloaded
-// CHECK:STDOUT:   %import_ref.6 = import_ref Main//export_export, inst+22, unloaded
-// CHECK:STDOUT:   %import_ref.7 = import_ref Main//export_export, inst+23, unloaded
+// CHECK:STDOUT:   %import_ref.3: type = import_ref Main//export_export, inst+20, loaded [template = constants.%NSC]
+// CHECK:STDOUT:   %import_ref.4 = import_ref Main//export_export, inst+11, unloaded
+// CHECK:STDOUT:   %import_ref.5 = import_ref Main//export_export, inst+12, unloaded
+// CHECK:STDOUT:   %import_ref.6 = import_ref Main//export_export, inst+18, unloaded
+// CHECK:STDOUT:   %import_ref.7 = import_ref Main//export_export, inst+19, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -612,11 +612,11 @@ private export C;
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1 = import_ref Main//base, inst+1, unloaded
-// CHECK:STDOUT:   %import_ref.2: <namespace> = import_ref Main//base, inst+13, loaded
+// CHECK:STDOUT:   %import_ref.2: <namespace> = import_ref Main//base, inst+11, loaded
 // CHECK:STDOUT:   %NS: <namespace> = namespace %import_ref.2, [template] {
 // CHECK:STDOUT:     .NSC = %import_ref.3
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.3 = import_ref Main//base, inst+14, unloaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref Main//base, inst+12, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -660,11 +660,11 @@ private export C;
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1: type = import_ref Main//base, inst+1, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.2: <namespace> = import_ref Main//base, inst+13, loaded
+// CHECK:STDOUT:   %import_ref.2: <namespace> = import_ref Main//base, inst+11, loaded
 // CHECK:STDOUT:   %NS: <namespace> = namespace %import_ref.2, [template] {
 // CHECK:STDOUT:     .NSC = %import_ref.3
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.3 = import_ref Main//base, inst+14, unloaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref Main//base, inst+12, unloaded
 // CHECK:STDOUT:   %import_ref.4 = import_ref Main//base, inst+2, unloaded
 // CHECK:STDOUT:   %import_ref.5 = import_ref Main//base, inst+7, unloaded
 // CHECK:STDOUT: }
@@ -702,15 +702,15 @@ private export C;
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1: type = import_ref Main//base, inst+1, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.2: <namespace> = import_ref Main//base, inst+13, loaded
+// CHECK:STDOUT:   %import_ref.2: <namespace> = import_ref Main//base, inst+11, loaded
 // CHECK:STDOUT:   %NS: <namespace> = namespace %import_ref.2, [template] {
 // CHECK:STDOUT:     .NSC = %import_ref.3
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.3: type = import_ref Main//base, inst+14, loaded [template = constants.%NSC]
+// CHECK:STDOUT:   %import_ref.3: type = import_ref Main//base, inst+12, loaded [template = constants.%NSC]
 // CHECK:STDOUT:   %import_ref.4 = import_ref Main//base, inst+2, unloaded
 // CHECK:STDOUT:   %import_ref.5 = import_ref Main//base, inst+7, unloaded
-// CHECK:STDOUT:   %import_ref.6 = import_ref Main//base, inst+15, unloaded
-// CHECK:STDOUT:   %import_ref.7 = import_ref Main//base, inst+19, unloaded
+// CHECK:STDOUT:   %import_ref.6 = import_ref Main//base, inst+13, unloaded
+// CHECK:STDOUT:   %import_ref.7 = import_ref Main//base, inst+17, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -781,16 +781,16 @@ private export C;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//export, inst+15, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//export, inst+13, loaded [template = constants.%C]
 // CHECK:STDOUT:   %import_ref.2: <namespace> = import_ref Main//export, inst+4, loaded
 // CHECK:STDOUT:   %NS: <namespace> = namespace %import_ref.2, [template] {
 // CHECK:STDOUT:     .NSC = %import_ref.3
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.3: type = import_ref Main//export, inst+24, loaded [template = constants.%NSC]
-// CHECK:STDOUT:   %import_ref.4 = import_ref Main//export, inst+13, unloaded
-// CHECK:STDOUT:   %import_ref.5 = import_ref Main//export, inst+14, unloaded
-// CHECK:STDOUT:   %import_ref.6 = import_ref Main//export, inst+22, unloaded
-// CHECK:STDOUT:   %import_ref.7 = import_ref Main//export, inst+23, unloaded
+// CHECK:STDOUT:   %import_ref.3: type = import_ref Main//export, inst+20, loaded [template = constants.%NSC]
+// CHECK:STDOUT:   %import_ref.4 = import_ref Main//export, inst+11, unloaded
+// CHECK:STDOUT:   %import_ref.5 = import_ref Main//export, inst+12, unloaded
+// CHECK:STDOUT:   %import_ref.6 = import_ref Main//export, inst+18, unloaded
+// CHECK:STDOUT:   %import_ref.7 = import_ref Main//export, inst+19, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -868,11 +868,11 @@ private export C;
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1: type = import_ref Main//base, inst+1, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.2: <namespace> = import_ref Main//base, inst+13, loaded
+// CHECK:STDOUT:   %import_ref.2: <namespace> = import_ref Main//base, inst+11, loaded
 // CHECK:STDOUT:   %NS: <namespace> = namespace %import_ref.2, [template] {
 // CHECK:STDOUT:     .NSC = %import_ref.3
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.3 = import_ref Main//base, inst+14, unloaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref Main//base, inst+12, unloaded
 // CHECK:STDOUT:   %import_ref.4 = import_ref Main//base, inst+2, unloaded
 // CHECK:STDOUT:   %import_ref.5 = import_ref Main//base, inst+7, unloaded
 // CHECK:STDOUT: }
@@ -905,9 +905,9 @@ private export C;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//repeat_export, inst+15, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.2 = import_ref Main//repeat_export, inst+13, unloaded
-// CHECK:STDOUT:   %import_ref.3 = import_ref Main//repeat_export, inst+14, unloaded
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//repeat_export, inst+13, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.2 = import_ref Main//repeat_export, inst+11, unloaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref Main//repeat_export, inst+12, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -951,11 +951,11 @@ private export C;
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1: type = import_ref Main//base, inst+1, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.2: <namespace> = import_ref Main//base, inst+13, loaded
+// CHECK:STDOUT:   %import_ref.2: <namespace> = import_ref Main//base, inst+11, loaded
 // CHECK:STDOUT:   %NS: <namespace> = namespace %import_ref.2, [template] {
 // CHECK:STDOUT:     .NSC = %import_ref.3
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.3 = import_ref Main//base, inst+14, unloaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref Main//base, inst+12, unloaded
 // CHECK:STDOUT:   %import_ref.4 = import_ref Main//base, inst+2, unloaded
 // CHECK:STDOUT:   %import_ref.5 = import_ref Main//base, inst+7, unloaded
 // CHECK:STDOUT: }

+ 26 - 26
toolchain/check/testdata/return/no_prelude/import_convert_function.carbon

@@ -917,7 +917,7 @@ fn F0(n: i32) -> P.D {
 // CHECK:STDOUT:   %import_ref.2: type = import_ref P//library, inst+29, loaded [template = constants.%D]
 // CHECK:STDOUT:   %import_ref.3 = import_ref P//library, inst+30, unloaded
 // CHECK:STDOUT:   %import_ref.4 = import_ref P//library, inst+35, unloaded
-// CHECK:STDOUT:   %import_ref.5 = import_ref P//library, inst+41, unloaded
+// CHECK:STDOUT:   %import_ref.5 = import_ref P//library, inst+39, unloaded
 // CHECK:STDOUT:   %import_ref.6: %C.type = import_ref P//library, inst+20, loaded [template = constants.%C.1]
 // CHECK:STDOUT:   %import_ref.7 = import_ref P//library, inst+25, unloaded
 // CHECK:STDOUT:   %import_ref.8: %ImplicitAs.type.1 = import_ref Core//default, inst+15, loaded [template = constants.%ImplicitAs]
@@ -926,31 +926,31 @@ fn F0(n: i32) -> P.D {
 // CHECK:STDOUT:   %import_ref.11 = import_ref Core//default, inst+36, unloaded
 // CHECK:STDOUT:   %import_ref.12 = import_ref Core//default, inst+36, unloaded
 // CHECK:STDOUT:   %import_ref.13 = import_ref Core//default, inst+36, unloaded
-// CHECK:STDOUT:   %import_ref.14: type = import_ref P//library, inst+72, loaded [template = constants.%C.3]
-// CHECK:STDOUT:   %import_ref.15: type = import_ref P//library, inst+117, loaded [template = constants.%ImplicitAs.type.3]
-// CHECK:STDOUT:   %import_ref.16: <witness> = import_ref P//library, inst+137, loaded [template = constants.%.22]
-// CHECK:STDOUT:   %import_ref.17: type = import_ref P//library, inst+147, loaded [template = constants.%C.4]
-// CHECK:STDOUT:   %import_ref.18: type = import_ref P//library, inst+152, loaded [template = constants.%ImplicitAs.type.3]
-// CHECK:STDOUT:   %import_ref.19: <witness> = import_ref P//library, inst+167, loaded [template = constants.%.23]
-// CHECK:STDOUT:   %import_ref.20: type = import_ref P//library, inst+176, loaded [template = constants.%C.5]
-// CHECK:STDOUT:   %import_ref.21: type = import_ref P//library, inst+181, loaded [template = constants.%ImplicitAs.type.3]
-// CHECK:STDOUT:   %import_ref.22: <witness> = import_ref P//library, inst+196, loaded [template = constants.%.24]
-// CHECK:STDOUT:   %import_ref.23: type = import_ref P//library, inst+205, loaded [template = constants.%C.6]
-// CHECK:STDOUT:   %import_ref.24: type = import_ref P//library, inst+210, loaded [template = constants.%ImplicitAs.type.3]
-// CHECK:STDOUT:   %import_ref.25: <witness> = import_ref P//library, inst+225, loaded [template = constants.%.25]
-// CHECK:STDOUT:   %import_ref.26: type = import_ref P//library, inst+234, loaded [template = constants.%C.7]
-// CHECK:STDOUT:   %import_ref.27: type = import_ref P//library, inst+239, loaded [template = constants.%ImplicitAs.type.3]
-// CHECK:STDOUT:   %import_ref.28: <witness> = import_ref P//library, inst+254, loaded [template = constants.%.26]
-// CHECK:STDOUT:   %import_ref.29: type = import_ref P//library, inst+263, loaded [template = constants.%C.8]
-// CHECK:STDOUT:   %import_ref.30: type = import_ref P//library, inst+268, loaded [template = constants.%ImplicitAs.type.3]
-// CHECK:STDOUT:   %import_ref.31: <witness> = import_ref P//library, inst+283, loaded [template = constants.%.27]
-// CHECK:STDOUT:   %import_ref.32: type = import_ref P//library, inst+292, loaded [template = constants.%C.9]
-// CHECK:STDOUT:   %import_ref.33: type = import_ref P//library, inst+297, loaded [template = constants.%ImplicitAs.type.3]
-// CHECK:STDOUT:   %import_ref.34: <witness> = import_ref P//library, inst+312, loaded [template = constants.%.28]
-// CHECK:STDOUT:   %import_ref.35: type = import_ref P//library, inst+321, loaded [template = constants.%C.10]
-// CHECK:STDOUT:   %import_ref.36: type = import_ref P//library, inst+326, loaded [template = constants.%ImplicitAs.type.3]
-// CHECK:STDOUT:   %import_ref.37: <witness> = import_ref P//library, inst+341, loaded [template = constants.%.29]
-// CHECK:STDOUT:   %import_ref.38: %Make.type = import_ref P//library, inst+52, loaded [template = constants.%Make]
+// CHECK:STDOUT:   %import_ref.14: type = import_ref P//library, inst+66, loaded [template = constants.%C.3]
+// CHECK:STDOUT:   %import_ref.15: type = import_ref P//library, inst+111, loaded [template = constants.%ImplicitAs.type.3]
+// CHECK:STDOUT:   %import_ref.16: <witness> = import_ref P//library, inst+131, loaded [template = constants.%.22]
+// CHECK:STDOUT:   %import_ref.17: type = import_ref P//library, inst+141, loaded [template = constants.%C.4]
+// CHECK:STDOUT:   %import_ref.18: type = import_ref P//library, inst+146, loaded [template = constants.%ImplicitAs.type.3]
+// CHECK:STDOUT:   %import_ref.19: <witness> = import_ref P//library, inst+161, loaded [template = constants.%.23]
+// CHECK:STDOUT:   %import_ref.20: type = import_ref P//library, inst+170, loaded [template = constants.%C.5]
+// CHECK:STDOUT:   %import_ref.21: type = import_ref P//library, inst+175, loaded [template = constants.%ImplicitAs.type.3]
+// CHECK:STDOUT:   %import_ref.22: <witness> = import_ref P//library, inst+190, loaded [template = constants.%.24]
+// CHECK:STDOUT:   %import_ref.23: type = import_ref P//library, inst+199, loaded [template = constants.%C.6]
+// CHECK:STDOUT:   %import_ref.24: type = import_ref P//library, inst+204, loaded [template = constants.%ImplicitAs.type.3]
+// CHECK:STDOUT:   %import_ref.25: <witness> = import_ref P//library, inst+219, loaded [template = constants.%.25]
+// CHECK:STDOUT:   %import_ref.26: type = import_ref P//library, inst+228, loaded [template = constants.%C.7]
+// CHECK:STDOUT:   %import_ref.27: type = import_ref P//library, inst+233, loaded [template = constants.%ImplicitAs.type.3]
+// CHECK:STDOUT:   %import_ref.28: <witness> = import_ref P//library, inst+248, loaded [template = constants.%.26]
+// CHECK:STDOUT:   %import_ref.29: type = import_ref P//library, inst+257, loaded [template = constants.%C.8]
+// CHECK:STDOUT:   %import_ref.30: type = import_ref P//library, inst+262, loaded [template = constants.%ImplicitAs.type.3]
+// CHECK:STDOUT:   %import_ref.31: <witness> = import_ref P//library, inst+277, loaded [template = constants.%.27]
+// CHECK:STDOUT:   %import_ref.32: type = import_ref P//library, inst+286, loaded [template = constants.%C.9]
+// CHECK:STDOUT:   %import_ref.33: type = import_ref P//library, inst+291, loaded [template = constants.%ImplicitAs.type.3]
+// CHECK:STDOUT:   %import_ref.34: <witness> = import_ref P//library, inst+306, loaded [template = constants.%.28]
+// CHECK:STDOUT:   %import_ref.35: type = import_ref P//library, inst+315, loaded [template = constants.%C.10]
+// CHECK:STDOUT:   %import_ref.36: type = import_ref P//library, inst+320, loaded [template = constants.%ImplicitAs.type.3]
+// CHECK:STDOUT:   %import_ref.37: <witness> = import_ref P//library, inst+335, loaded [template = constants.%.29]
+// CHECK:STDOUT:   %import_ref.38: %Make.type = import_ref P//library, inst+48, loaded [template = constants.%Make]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {

+ 15 - 15
toolchain/check/testdata/struct/import.carbon

@@ -247,17 +247,17 @@ var c_bad: C({.a = 3, .b = 4}) = F();
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref.1: ref %.2 = import_ref Implicit//default, inst+19, loaded
-// CHECK:STDOUT:   %import_ref.2: ref %.6 = import_ref Implicit//default, inst+59, loaded
-// CHECK:STDOUT:   %import_ref.3: %C.type = import_ref Implicit//default, inst+104, loaded [template = constants.%C.1]
-// CHECK:STDOUT:   %import_ref.4: %F.type = import_ref Implicit//default, inst+131, loaded [template = constants.%F]
+// CHECK:STDOUT:   %import_ref.1: ref %.2 = import_ref Implicit//default, inst+17, loaded
+// CHECK:STDOUT:   %import_ref.2: ref %.6 = import_ref Implicit//default, inst+47, loaded
+// CHECK:STDOUT:   %import_ref.3: %C.type = import_ref Implicit//default, inst+86, loaded [template = constants.%C.1]
+// CHECK:STDOUT:   %import_ref.4: %F.type = import_ref Implicit//default, inst+111, loaded [template = constants.%F]
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
 // CHECK:STDOUT:     .Int32 = %import_ref.5
 // CHECK:STDOUT:     import Core//prelude
 // CHECK:STDOUT:     import Core//prelude/...
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %import_ref.5: %Int32.type = import_ref Core//prelude/types, inst+15, loaded [template = constants.%Int32]
-// CHECK:STDOUT:   %import_ref.6 = import_ref Implicit//default, inst+109, unloaded
+// CHECK:STDOUT:   %import_ref.6 = import_ref Implicit//default, inst+91, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -396,15 +396,15 @@ var c_bad: C({.a = 3, .b = 4}) = F();
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref.1 = import_ref Implicit//default, inst+19, unloaded
-// CHECK:STDOUT:   %import_ref.2 = import_ref Implicit//default, inst+59, unloaded
-// CHECK:STDOUT:   %import_ref.3: %C.type = import_ref Implicit//default, inst+104, loaded [template = constants.%C.1]
-// CHECK:STDOUT:   %import_ref.4: %F.type = import_ref Implicit//default, inst+131, loaded [template = constants.%F]
+// CHECK:STDOUT:   %import_ref.1 = import_ref Implicit//default, inst+17, unloaded
+// CHECK:STDOUT:   %import_ref.2 = import_ref Implicit//default, inst+47, unloaded
+// CHECK:STDOUT:   %import_ref.3: %C.type = import_ref Implicit//default, inst+86, loaded [template = constants.%C.1]
+// CHECK:STDOUT:   %import_ref.4: %F.type = import_ref Implicit//default, inst+111, loaded [template = constants.%F]
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
 // CHECK:STDOUT:     import Core//prelude
 // CHECK:STDOUT:     import Core//prelude/...
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.5 = import_ref Implicit//default, inst+109, unloaded
+// CHECK:STDOUT:   %import_ref.5 = import_ref Implicit//default, inst+91, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -506,16 +506,16 @@ var c_bad: C({.a = 3, .b = 4}) = F();
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref.1 = import_ref Implicit//default, inst+19, unloaded
-// CHECK:STDOUT:   %import_ref.2 = import_ref Implicit//default, inst+59, unloaded
-// CHECK:STDOUT:   %import_ref.3: %C.type = import_ref Implicit//default, inst+104, loaded [template = constants.%C.1]
-// CHECK:STDOUT:   %import_ref.4: %F.type = import_ref Implicit//default, inst+131, loaded [template = constants.%F]
+// CHECK:STDOUT:   %import_ref.1 = import_ref Implicit//default, inst+17, unloaded
+// CHECK:STDOUT:   %import_ref.2 = import_ref Implicit//default, inst+47, unloaded
+// CHECK:STDOUT:   %import_ref.3: %C.type = import_ref Implicit//default, inst+86, loaded [template = constants.%C.1]
+// CHECK:STDOUT:   %import_ref.4: %F.type = import_ref Implicit//default, inst+111, loaded [template = constants.%F]
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
 // CHECK:STDOUT:     .ImplicitAs = %import_ref.6
 // CHECK:STDOUT:     import Core//prelude
 // CHECK:STDOUT:     import Core//prelude/...
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.5 = import_ref Implicit//default, inst+109, unloaded
+// CHECK:STDOUT:   %import_ref.5 = import_ref Implicit//default, inst+91, unloaded
 // CHECK:STDOUT:   %import_ref.6: %ImplicitAs.type.1 = import_ref Core//prelude/operators/as, inst+49, loaded [template = constants.%ImplicitAs]
 // CHECK:STDOUT:   %import_ref.7 = import_ref Core//prelude/operators/as, inst+55, unloaded
 // CHECK:STDOUT:   %import_ref.8: @ImplicitAs.%.1 (%.11) = import_ref Core//prelude/operators/as, inst+77, loaded [symbolic = @ImplicitAs.%.2 (constants.%.15)]

+ 0 - 7
toolchain/lower/constant.cpp

@@ -234,13 +234,6 @@ static auto EmitAsConstant(ConstantContext& /*context*/,
   CARBON_FATAL("TODO: Add support: {0}", inst);
 }
 
-static auto EmitAsConstant(ConstantContext& /*context*/,
-                           SemIR::StructTypeField /*inst*/) -> llvm::Constant* {
-  // A StructTypeField isn't a value, so this constant value won't ever be used.
-  // It also doesn't even have a type, so we can't use GetUnusedConstant.
-  return nullptr;
-}
-
 auto LowerConstants(FileContext& file_context,
                     llvm::MutableArrayRef<llvm::Constant*> constants) -> void {
   ConstantContext context(file_context, constants);

+ 3 - 5
toolchain/lower/file_context.cpp

@@ -548,13 +548,11 @@ static auto BuildTypeForInst(FileContext& context, SemIR::PointerType /*inst*/)
 
 static auto BuildTypeForInst(FileContext& context, SemIR::StructType inst)
     -> llvm::Type* {
-  auto fields = context.sem_ir().inst_blocks().Get(inst.fields_id);
+  auto fields = context.sem_ir().struct_type_fields().Get(inst.fields_id);
   llvm::SmallVector<llvm::Type*> subtypes;
   subtypes.reserve(fields.size());
-  for (auto field_id : fields) {
-    auto field =
-        context.sem_ir().insts().GetAs<SemIR::StructTypeField>(field_id);
-    subtypes.push_back(context.GetType(field.field_type_id));
+  for (auto field : fields) {
+    subtypes.push_back(context.GetType(field.type_id));
   }
   return llvm::StructType::get(context.llvm_context(), subtypes);
 }

+ 5 - 13
toolchain/lower/handle_aggregates.cpp

@@ -91,14 +91,11 @@ static auto GetAggregateElement(FunctionContext& context,
 static auto GetStructFieldName(FunctionContext& context,
                                SemIR::TypeId struct_type_id,
                                SemIR::ElementIndex index) -> llvm::StringRef {
-  auto fields = context.sem_ir().inst_blocks().Get(
-      context.sem_ir()
-          .types()
-          .GetAs<SemIR::StructType>(struct_type_id)
-          .fields_id);
-  auto field = context.sem_ir().insts().GetAs<SemIR::StructTypeField>(
-      fields[index.index]);
-  return context.sem_ir().names().GetIRBaseName(field.name_id);
+  auto struct_type =
+      context.sem_ir().types().GetAs<SemIR::StructType>(struct_type_id);
+  auto fields =
+      context.sem_ir().struct_type_fields().Get(struct_type.fields_id);
+  return context.sem_ir().names().GetIRBaseName(fields[index.index].name_id);
 }
 
 auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
@@ -237,11 +234,6 @@ auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
       inst_id, EmitAggregateValueRepr(context, inst.type_id, inst.elements_id));
 }
 
-auto HandleInst(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/,
-                SemIR::StructTypeField /*inst*/) -> void {
-  // No action to take.
-}
-
 auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
                 SemIR::TupleAccess inst) -> void {
   context.SetLocal(inst_id,

+ 1 - 0
toolchain/sem_ir/BUILD

@@ -110,6 +110,7 @@ cc_library(
         "interface.h",
         "name.h",
         "name_scope.h",
+        "struct_type_field.h",
         "type.h",
         "type_info.h",
     ],

+ 2 - 0
toolchain/sem_ir/copy_on_write_block.h

@@ -68,6 +68,8 @@ class CopyOnWriteBlock {
 };
 
 using CopyOnWriteInstBlock = CopyOnWriteBlock<InstBlockId, &File::inst_blocks>;
+using CopyOnWriteStructTypeFieldsBlock =
+    CopyOnWriteBlock<StructTypeFieldsId, &File::struct_type_fields>;
 using CopyOnWriteTypeBlock = CopyOnWriteBlock<TypeBlockId, &File::type_blocks>;
 
 }  // namespace Carbon::SemIR

+ 3 - 1
toolchain/sem_ir/file.cpp

@@ -111,6 +111,7 @@ auto File::OutputYaml(bool include_builtins) const -> Yaml::OutputMapping {
           map.Add("classes", classes_.OutputYaml());
           map.Add("generics", generics_.OutputYaml());
           map.Add("specifics", specifics_.OutputYaml());
+          map.Add("struct_type_fields", struct_type_fields_.OutputYaml());
           map.Add("types", types_.OutputYaml());
           map.Add("type_blocks", type_blocks_.OutputYaml());
           map.Add(
@@ -163,6 +164,8 @@ auto File::CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
   mem_usage.Collect(MemUsage::ConcatLabel(label, "import_irs_"), import_irs_);
   mem_usage.Collect(MemUsage::ConcatLabel(label, "import_ir_insts_"),
                     import_ir_insts_);
+  mem_usage.Collect(MemUsage::ConcatLabel(label, "struct_type_fields_"),
+                    struct_type_fields_);
   mem_usage.Collect(MemUsage::ConcatLabel(label, "type_blocks_"), type_blocks_);
   mem_usage.Collect(MemUsage::ConcatLabel(label, "insts_"), insts_);
   mem_usage.Collect(MemUsage::ConcatLabel(label, "name_scopes_"), name_scopes_);
@@ -202,7 +205,6 @@ auto GetExprCategory(const File& file, InstId inst_id) -> ExprCategory {
       case Return::Kind:
       case ReturnSlotPattern::Kind:
       case ReturnExpr::Kind:
-      case StructTypeField::Kind:
         return ExprCategory::NotExpr;
 
       case ImportRefUnloaded::Kind:

+ 10 - 0
toolchain/sem_ir/file.h

@@ -26,6 +26,7 @@
 #include "toolchain/sem_ir/interface.h"
 #include "toolchain/sem_ir/name.h"
 #include "toolchain/sem_ir/name_scope.h"
+#include "toolchain/sem_ir/struct_type_field.h"
 #include "toolchain/sem_ir/type.h"
 #include "toolchain/sem_ir/type_info.h"
 
@@ -142,6 +143,12 @@ class File : public Printable<File> {
   }
   auto name_scopes() -> NameScopeStore& { return name_scopes_; }
   auto name_scopes() const -> const NameScopeStore& { return name_scopes_; }
+  auto struct_type_fields() -> StructTypeFieldsStore& {
+    return struct_type_fields_;
+  }
+  auto struct_type_fields() const -> const StructTypeFieldsStore& {
+    return struct_type_fields_;
+  }
   auto types() -> TypeStore& { return types_; }
   auto types() const -> const TypeStore& { return types_; }
   auto type_blocks() -> BlockValueStore<TypeBlockId>& { return type_blocks_; }
@@ -256,6 +263,9 @@ class File : public Printable<File> {
   // types.
   ConstantStore constants_;
 
+  // Storage for StructTypeField lists.
+  StructTypeFieldsStore struct_type_fields_ = StructTypeFieldsStore(allocator_);
+
   // Descriptions of types used in this file.
   TypeStore types_ = TypeStore(&insts_, &constant_values_);
 };

+ 2 - 14
toolchain/sem_ir/formatter.cpp

@@ -342,14 +342,6 @@ class FormatterImpl {
              sem_ir_.inst_blocks().GetOrEmpty(generic.GetEvalBlock(region)),
              sem_ir_.inst_blocks().GetOrEmpty(
                  specific.GetValueBlock(region)))) {
-      if (generic_inst_id && specific_inst_id &&
-          sem_ir_.insts().Is<StructTypeField>(*generic_inst_id) &&
-          sem_ir_.insts().Is<StructTypeField>(*specific_inst_id)) {
-        // Skip printing struct type fields to match the way we print the
-        // generic.
-        continue;
-      }
-
       Indent();
       if (generic_inst_id) {
         FormatName(*generic_inst_id);
@@ -899,18 +891,14 @@ class FormatterImpl {
     FormatTrailingBlock(inst.requirements_id);
   }
 
-  // StructTypeFields are formatted as part of their StructType.
-  auto FormatInst(InstId /*inst_id*/, StructTypeField /*inst*/) -> void {}
-
   auto FormatInstRHS(StructType inst) -> void {
     out_ << " {";
     llvm::ListSeparator sep;
-    for (auto field_id : sem_ir_.inst_blocks().Get(inst.fields_id)) {
+    for (auto field : sem_ir_.struct_type_fields().Get(inst.fields_id)) {
       out_ << sep << ".";
-      auto field = sem_ir_.insts().GetAs<StructTypeField>(field_id);
       FormatName(field.name_id);
       out_ << ": ";
-      FormatType(field.field_type_id);
+      FormatType(field.type_id);
     }
     out_ << "}";
   }

+ 3 - 2
toolchain/sem_ir/id_kind.h

@@ -123,8 +123,9 @@ using IdKind = TypeEnum<
     InstId, AbsoluteInstId, MatchingInstId, ConstantId, EntityNameId,
     CompileTimeBindIndex, RuntimeParamIndex, FacetTypeId, FunctionId, ClassId,
     InterfaceId, ImplId, GenericId, SpecificId, ImportIRId, ImportIRInstId,
-    LocId, BoolValue, IntKind, NameId, NameScopeId, InstBlockId, TypeId,
-    TypeBlockId, ElementIndex, LibraryNameId, FloatKind>;
+    LocId, BoolValue, IntKind, NameId, NameScopeId, InstBlockId,
+    StructTypeFieldsId, TypeId, TypeBlockId, ElementIndex, LibraryNameId,
+    FloatKind>;
 
 }  // namespace Carbon::SemIR
 

+ 20 - 0
toolchain/sem_ir/ids.h

@@ -29,6 +29,7 @@ struct ImportIRInst;
 struct Impl;
 struct Interface;
 struct NameScope;
+struct StructTypeField;
 struct TypeInfo;
 
 // The ID of an instruction.
@@ -722,6 +723,25 @@ constexpr InstBlockId InstBlockId::GlobalInit = InstBlockId(3);
 constexpr InstBlockId InstBlockId::Invalid = InstBlockId(InvalidIndex);
 constexpr InstBlockId InstBlockId::Unreachable = InstBlockId(InvalidIndex - 1);
 
+// The ID of a type block.
+struct StructTypeFieldsId : public IdBase,
+                            public Printable<StructTypeFieldsId> {
+  using ElementType = StructTypeField;
+  using ValueType = llvm::MutableArrayRef<StructTypeField>;
+
+  // An explicitly invalid ID.
+  static const StructTypeFieldsId Invalid;
+
+  using IdBase::IdBase;
+  auto Print(llvm::raw_ostream& out) const -> void {
+    out << "type_block";
+    IdBase::Print(out);
+  }
+};
+
+constexpr StructTypeFieldsId StructTypeFieldsId::Invalid =
+    StructTypeFieldsId(InvalidIndex);
+
 // The ID of a type.
 struct TypeId : public IdBase, public Printable<TypeId> {
   // `StringifyTypeExpr` is used for diagnostics. However, where possible, an

+ 0 - 1
toolchain/sem_ir/inst_kind.def

@@ -91,7 +91,6 @@ CARBON_SEM_IR_INST_KIND(StructAccess)
 CARBON_SEM_IR_INST_KIND(StructInit)
 CARBON_SEM_IR_INST_KIND(StructLiteral)
 CARBON_SEM_IR_INST_KIND(StructType)
-CARBON_SEM_IR_INST_KIND(StructTypeField)
 CARBON_SEM_IR_INST_KIND(StructValue)
 CARBON_SEM_IR_INST_KIND(SymbolicBindingPattern)
 CARBON_SEM_IR_INST_KIND(TemporaryStorage)

+ 9 - 13
toolchain/sem_ir/stringify_type.cpp

@@ -206,26 +206,22 @@ auto StringifyTypeExpr(const SemIR::File& outer_sem_ir, InstId outer_inst_id)
         break;
       }
       case CARBON_KIND(StructType inst): {
-        auto refs = sem_ir.inst_blocks().Get(inst.fields_id);
-        if (refs.empty()) {
+        auto fields = sem_ir.struct_type_fields().Get(inst.fields_id);
+        if (fields.empty()) {
           out << "{}";
           break;
-        } else if (step.index == 0) {
-          out << "{";
-        } else if (step.index < static_cast<int>(refs.size())) {
-          out << ", ";
-        } else {
+        }
+
+        if (step.index >= static_cast<int>(fields.size())) {
           out << "}";
           break;
         }
 
+        const auto& field = fields[step.index];
+        out << (step.index == 0 ? "{" : ", ") << "."
+            << sem_ir.names().GetFormatted(field.name_id) << ": ";
         steps.push_back(step.Next());
-        push_inst_id(refs[step.index]);
-        break;
-      }
-      case CARBON_KIND(StructTypeField inst): {
-        out << "." << sem_ir.names().GetFormatted(inst.name_id) << ": ";
-        push_inst_id(sem_ir.types().GetInstId(inst.field_type_id));
+        push_inst_id(sem_ir.types().GetInstId(field.type_id));
         break;
       }
       case CARBON_KIND(TupleType inst): {

+ 39 - 0
toolchain/sem_ir/struct_type_field.h

@@ -0,0 +1,39 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef CARBON_TOOLCHAIN_SEM_IR_STRUCT_TYPE_FIELD_H_
+#define CARBON_TOOLCHAIN_SEM_IR_STRUCT_TYPE_FIELD_H_
+
+#include "toolchain/sem_ir/block_value_store.h"
+#include "toolchain/sem_ir/ids.h"
+
+namespace Carbon::SemIR {
+
+// A field in a struct's type, such as `.a: i32` in `{.a: i32}`.
+struct StructTypeField : Printable<StructTypeField> {
+  auto Print(llvm::raw_ostream& out) const -> void {
+    out << "{name_id: " << name_id << ", type_id: " << type_id << "}";
+  }
+
+  friend auto operator==(StructTypeField lhs, StructTypeField rhs) -> bool {
+    return std::memcmp(&lhs, &rhs, sizeof(StructTypeField)) == 0;
+  }
+
+  NameId name_id;
+  TypeId type_id;
+};
+
+using StructTypeFieldsStore = BlockValueStore<StructTypeFieldsId>;
+
+// See common/hashing.h. Supports canonicalization of fields.
+inline auto CarbonHashValue(const StructTypeField& value, uint64_t seed)
+    -> HashCode {
+  Hasher hasher(seed);
+  hasher.HashRaw(value);
+  return static_cast<HashCode>(hasher);
+}
+
+}  // namespace Carbon::SemIR
+
+#endif  // CARBON_TOOLCHAIN_SEM_IR_STRUCT_TYPE_FIELD_H_

+ 1 - 16
toolchain/sem_ir/typed_insts.h

@@ -1117,22 +1117,7 @@ struct StructType {
            .constant_kind = InstConstantKind::Conditional});
 
   TypeId type_id;
-  InstBlockId fields_id;
-};
-
-// A field in a struct's type, such as `.a: i32` in `{.a: i32}`.
-//
-// This instruction is an implementation detail of `StructType`, and doesn't
-// produce a value. As a consequence, although there's a type for the field, the
-// instruction has no type.
-struct StructTypeField {
-  // TODO: Make Parse::NodeId more specific.
-  static constexpr auto Kind = InstKind::StructTypeField.Define<Parse::NodeId>(
-      {.ir_name = "struct_type_field",
-       .constant_kind = InstConstantKind::Conditional});
-
-  NameId name_id;
-  TypeId field_type_id;
+  StructTypeFieldsId fields_id;
 };
 
 // A struct value.

+ 1 - 0
toolchain/sem_ir/yaml_test.cpp

@@ -63,6 +63,7 @@ TEST(SemIRTest, YAML) {
       Pair("classes", Yaml::Mapping(SizeIs(0))),
       Pair("generics", Yaml::Mapping(SizeIs(0))),
       Pair("specifics", Yaml::Mapping(SizeIs(0))),
+      Pair("struct_type_fields", Yaml::Mapping(SizeIs(0))),
       Pair("types", Yaml::Mapping(Each(type_builtin))),
       Pair("type_blocks", Yaml::Mapping(SizeIs(Ge(1)))),
       Pair("insts",