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

Add SemIR instruction to track that a conversion was performed. (#3363)

Instead of ad-hoc conversion tracking on some kinds of nodes that
conversion creates, consolidate tracking into a single node kind. This
frees up an operand on `Init` instructions that can be used to store the
destination.
Richard Smith 2 лет назад
Родитель
Сommit
6d5e62974c
100 измененных файлов с 733 добавлено и 489 удалено
  1. 4 0
      toolchain/check/context.cpp
  2. 55 44
      toolchain/check/convert.cpp
  3. 4 2
      toolchain/check/testdata/array/array_in_place.carbon
  4. 6 4
      toolchain/check/testdata/array/assign_return_value.carbon
  5. 8 5
      toolchain/check/testdata/array/assign_var.carbon
  6. 31 12
      toolchain/check/testdata/array/base.carbon
  7. 3 1
      toolchain/check/testdata/array/fail_type_mismatch.carbon
  8. 8 6
      toolchain/check/testdata/array/function_param.carbon
  9. 3 2
      toolchain/check/testdata/array/nine_elements.carbon
  10. 3 2
      toolchain/check/testdata/as/as_type.carbon
  11. 3 1
      toolchain/check/testdata/as/fail_no_conversion.carbon
  12. 11 5
      toolchain/check/testdata/as/tuple.carbon
  13. 6 4
      toolchain/check/testdata/basics/numeric_literals.carbon
  14. 39 34
      toolchain/check/testdata/basics/raw_and_textual_ir.carbon
  15. 36 32
      toolchain/check/testdata/basics/raw_ir.carbon
  16. 3 2
      toolchain/check/testdata/basics/textual_ir.carbon
  17. 3 2
      toolchain/check/testdata/class/basic.carbon
  18. 3 0
      toolchain/check/testdata/class/fail_init.carbon
  19. 3 2
      toolchain/check/testdata/class/fail_init_as_inplace.carbon
  20. 3 3
      toolchain/check/testdata/class/fail_redeclaration_scope.carbon
  21. 2 2
      toolchain/check/testdata/class/fail_redefinition.carbon
  22. 6 4
      toolchain/check/testdata/class/init.carbon
  23. 3 2
      toolchain/check/testdata/class/init_as.carbon
  24. 3 2
      toolchain/check/testdata/class/init_nested.carbon
  25. 18 12
      toolchain/check/testdata/class/method.carbon
  26. 1 1
      toolchain/check/testdata/class/nested.carbon
  27. 1 1
      toolchain/check/testdata/class/nested_name.carbon
  28. 3 2
      toolchain/check/testdata/class/reenter_scope.carbon
  29. 7 4
      toolchain/check/testdata/class/scope.carbon
  30. 3 2
      toolchain/check/testdata/class/self_type.carbon
  31. 3 2
      toolchain/check/testdata/class/static_method.carbon
  32. 1 0
      toolchain/check/testdata/expression_category/in_place_tuple_initialization.carbon
  33. 3 2
      toolchain/check/testdata/function/call/empty_struct.carbon
  34. 3 2
      toolchain/check/testdata/function/call/empty_tuple.carbon
  35. 2 1
      toolchain/check/testdata/function/call/return_implicit.carbon
  36. 10 6
      toolchain/check/testdata/if_expression/constant_condition.carbon
  37. 5 3
      toolchain/check/testdata/if_expression/control_flow.carbon
  38. 2 2
      toolchain/check/testdata/if_expression/fail_not_in_function.carbon
  39. 9 6
      toolchain/check/testdata/if_expression/struct.carbon
  40. 3 2
      toolchain/check/testdata/index/array_element_access.carbon
  41. 6 4
      toolchain/check/testdata/index/expression_category.carbon
  42. 3 2
      toolchain/check/testdata/index/fail_array_large_index.carbon
  43. 3 2
      toolchain/check/testdata/index/fail_array_non_int_indexing.carbon
  44. 3 2
      toolchain/check/testdata/index/fail_array_out_of_bound_access.carbon
  45. 2 1
      toolchain/check/testdata/index/fail_invalid_base.carbon
  46. 5 3
      toolchain/check/testdata/index/fail_non_deterministic_type.carbon
  47. 5 3
      toolchain/check/testdata/index/fail_tuple_index_error.carbon
  48. 9 5
      toolchain/check/testdata/index/fail_tuple_large_index.carbon
  49. 5 3
      toolchain/check/testdata/index/fail_tuple_non_int_indexing.carbon
  50. 5 3
      toolchain/check/testdata/index/fail_tuple_out_of_bound_access.carbon
  51. 9 5
      toolchain/check/testdata/index/tuple_element_access.carbon
  52. 3 2
      toolchain/check/testdata/index/tuple_return_value_access.carbon
  53. 9 5
      toolchain/check/testdata/let/convert.carbon
  54. 8 6
      toolchain/check/testdata/operators/and.carbon
  55. 8 5
      toolchain/check/testdata/operators/assignment.carbon
  56. 15 9
      toolchain/check/testdata/operators/fail_assignment_to_non_assignable.carbon
  57. 9 7
      toolchain/check/testdata/operators/or.carbon
  58. 8 5
      toolchain/check/testdata/pointer/address_of_lvalue.carbon
  59. 3 2
      toolchain/check/testdata/pointer/fail_address_of_value.carbon
  60. 6 4
      toolchain/check/testdata/pointer/fail_dereference_not_pointer.carbon
  61. 3 2
      toolchain/check/testdata/return/struct.carbon
  62. 3 2
      toolchain/check/testdata/return/tuple.carbon
  63. 9 5
      toolchain/check/testdata/struct/empty.carbon
  64. 2 1
      toolchain/check/testdata/struct/fail_assign_nested.carbon
  65. 2 1
      toolchain/check/testdata/struct/fail_assign_to_empty.carbon
  66. 3 2
      toolchain/check/testdata/struct/fail_member_access_type.carbon
  67. 3 2
      toolchain/check/testdata/struct/fail_non_member_access.carbon
  68. 5 3
      toolchain/check/testdata/struct/literal_member_access.carbon
  69. 3 2
      toolchain/check/testdata/struct/member_access.carbon
  70. 5 2
      toolchain/check/testdata/struct/nested_struct_in_place.carbon
  71. 6 4
      toolchain/check/testdata/struct/one_entry.carbon
  72. 12 7
      toolchain/check/testdata/struct/reorder_fields.carbon
  73. 16 10
      toolchain/check/testdata/struct/tuple_as_element.carbon
  74. 6 4
      toolchain/check/testdata/struct/two_entries.carbon
  75. 9 5
      toolchain/check/testdata/tuples/empty.carbon
  76. 2 1
      toolchain/check/testdata/tuples/fail_assign_empty.carbon
  77. 4 1
      toolchain/check/testdata/tuples/fail_assign_nested.carbon
  78. 2 1
      toolchain/check/testdata/tuples/fail_assign_to_empty.carbon
  79. 2 1
      toolchain/check/testdata/tuples/fail_element_type_mismatch.carbon
  80. 2 1
      toolchain/check/testdata/tuples/fail_nested_incomplete.carbon
  81. 2 1
      toolchain/check/testdata/tuples/fail_too_few_element.carbon
  82. 2 1
      toolchain/check/testdata/tuples/fail_type_assign.carbon
  83. 2 1
      toolchain/check/testdata/tuples/fail_value_as_type.carbon
  84. 8 4
      toolchain/check/testdata/tuples/nested_tuple.carbon
  85. 13 6
      toolchain/check/testdata/tuples/nested_tuple_in_place.carbon
  86. 9 5
      toolchain/check/testdata/tuples/one_element.carbon
  87. 9 5
      toolchain/check/testdata/tuples/two_elements.carbon
  88. 24 16
      toolchain/check/testdata/while/break_continue.carbon
  89. 3 2
      toolchain/check/testdata/while/unreachable_end.carbon
  90. 3 2
      toolchain/check/testdata/while/while.carbon
  91. 18 0
      toolchain/lower/file_context.cpp
  92. 6 0
      toolchain/lower/file_context.h
  93. 2 14
      toolchain/lower/function_context.cpp
  94. 6 10
      toolchain/lower/function_context.h
  95. 21 20
      toolchain/lower/handle.cpp
  96. 4 4
      toolchain/lower/handle_aggregates.cpp
  97. 5 5
      toolchain/lower/handle_expression_category.cpp
  98. 21 16
      toolchain/lower/testdata/array/base.carbon
  99. 7 0
      toolchain/sem_ir/file.cpp
  100. 22 21
      toolchain/sem_ir/formatter.cpp

+ 4 - 0
toolchain/check/context.cpp

@@ -788,6 +788,7 @@ class TypeCompleter {
       case SemIR::ClassDeclaration::Kind:
       case SemIR::ClassFieldAccess::Kind:
       case SemIR::ClassInit::Kind:
+      case SemIR::Converted::Kind:
       case SemIR::Dereference::Kind:
       case SemIR::Field::Kind:
       case SemIR::FunctionDeclaration::Kind:
@@ -1019,6 +1020,9 @@ auto Context::CanonicalizeTypeAndAddInstIfNew(SemIR::Inst inst)
 }
 
 auto Context::CanonicalizeType(SemIR::InstId inst_id) -> SemIR::TypeId {
+  while (auto converted = insts().Get(inst_id).TryAs<SemIR::Converted>()) {
+    inst_id = converted->result_id;
+  }
   inst_id = FollowNameReferences(inst_id);
 
   auto it = canonical_types_.find(inst_id);

+ 55 - 44
toolchain/check/convert.cpp

@@ -24,36 +24,39 @@ namespace Carbon::Check {
 static auto FindReturnSlotForInitializer(SemIR::File& sem_ir,
                                          SemIR::InstId init_id)
     -> SemIR::InstId {
-  SemIR::Inst init = sem_ir.insts().Get(init_id);
-  switch (init.kind()) {
-    default:
-      CARBON_FATAL() << "Initialization from unexpected inst " << init;
-
-    case SemIR::ClassInit::Kind:
-    case SemIR::StructInit::Kind:
-    case SemIR::TupleInit::Kind:
-      // TODO: Track a return slot for these initializers.
-      CARBON_FATAL() << init
-                     << " should be created with its return slot already "
-                        "filled in properly";
-
-    case SemIR::InitializeFrom::Kind: {
-      return init.As<SemIR::InitializeFrom>().dest_id;
-    }
+  while (true) {
+    SemIR::Inst init = sem_ir.insts().Get(init_id);
+    switch (init.kind()) {
+      default:
+        CARBON_FATAL() << "Initialization from unexpected inst " << init;
 
-    case SemIR::Call::Kind: {
-      auto call = init.As<SemIR::Call>();
-      if (!SemIR::GetInitializingRepresentation(sem_ir, call.type_id)
-               .has_return_slot()) {
-        return SemIR::InstId::Invalid;
-      }
-      return sem_ir.inst_blocks().Get(call.args_id).back();
-    }
+      case SemIR::Converted::Kind:
+        init_id = init.As<SemIR::Converted>().result_id;
+        continue;
+
+      case SemIR::ArrayInit::Kind:
+        return init.As<SemIR::ArrayInit>().dest_id;
+
+      case SemIR::ClassInit::Kind:
+        return init.As<SemIR::ClassInit>().dest_id;
+
+      case SemIR::StructInit::Kind:
+        return init.As<SemIR::StructInit>().dest_id;
+
+      case SemIR::TupleInit::Kind:
+        return init.As<SemIR::TupleInit>().dest_id;
 
-    case SemIR::ArrayInit::Kind: {
-      return sem_ir.inst_blocks()
-          .Get(init.As<SemIR::ArrayInit>().inits_and_return_slot_id)
-          .back();
+      case SemIR::InitializeFrom::Kind:
+        return init.As<SemIR::InitializeFrom>().dest_id;
+
+      case SemIR::Call::Kind: {
+        auto call = init.As<SemIR::Call>();
+        if (!SemIR::GetInitializingRepresentation(sem_ir, call.type_id)
+                 .has_return_slot()) {
+          return SemIR::InstId::Invalid;
+        }
+        return sem_ir.inst_blocks().Get(call.args_id).back();
+      }
     }
   }
 }
@@ -302,14 +305,12 @@ static auto ConvertTupleToArray(Context& context, SemIR::TupleType tuple_type,
     inits.push_back(init_id);
   }
 
-  // The last element of the refs block contains the return slot for the array
-  // initialization. Flush the temporary here if we didn't insert it earlier.
+  // Flush the temporary here if we didn't insert it earlier, so we can add a
+  // reference to the return slot.
   target_block->InsertHere();
-  inits.push_back(return_slot_id);
-
   return context.AddInst(SemIR::ArrayInit{value.parse_node(), target.type_id,
-                                          value_id,
-                                          sem_ir.inst_blocks().Add(inits)});
+                                          sem_ir.inst_blocks().Add(inits),
+                                          return_slot_id});
 }
 
 // Performs a conversion from a tuple to a tuple type. This function only
@@ -378,12 +379,14 @@ static auto ConvertTupleToTuple(Context& context, SemIR::TupleType src_type,
     new_block.Set(i, init_id);
   }
 
-  return is_init ? context.AddInst(SemIR::TupleInit{value.parse_node(),
-                                                    target.type_id, value_id,
-                                                    new_block.id()})
-                 : context.AddInst(SemIR::TupleValue{value.parse_node(),
-                                                     target.type_id, value_id,
-                                                     new_block.id()});
+  if (is_init) {
+    target.init_block->InsertHere();
+    return context.AddInst(SemIR::TupleInit{value.parse_node(), target.type_id,
+                                            new_block.id(), target.init_id});
+  } else {
+    return context.AddInst(
+        SemIR::TupleValue{value.parse_node(), target.type_id, new_block.id()});
+  }
 }
 
 // Common implementation for ConvertStructToStruct and ConvertStructToClass.
@@ -502,16 +505,18 @@ static auto ConvertStructToStructOrClass(Context& context,
   }
 
   if (is_class) {
+    target.init_block->InsertHere();
     CARBON_CHECK(is_init)
         << "Converting directly to a class value is not supported";
     return context.AddInst(SemIR::ClassInit{value.parse_node(), target.type_id,
-                                            value_id, new_block.id()});
+                                            new_block.id(), target.init_id});
   } else if (is_init) {
+    target.init_block->InsertHere();
     return context.AddInst(SemIR::StructInit{value.parse_node(), target.type_id,
-                                             value_id, new_block.id()});
+                                             new_block.id(), target.init_id});
   } else {
-    return context.AddInst(SemIR::StructValue{
-        value.parse_node(), target.type_id, value_id, new_block.id()});
+    return context.AddInst(
+        SemIR::StructValue{value.parse_node(), target.type_id, new_block.id()});
   }
 }
 
@@ -827,6 +832,12 @@ auto Convert(Context& context, Parse::Node parse_node, SemIR::InstId expr_id,
     return SemIR::InstId::BuiltinError;
   }
 
+  // Track that we performed a type conversion, if we did so.
+  if (orig_expr_id != expr_id) {
+    expr_id = context.AddInst(SemIR::Converted{
+        expr.parse_node(), target.type_id, orig_expr_id, expr_id});
+  }
+
   // For `as`, don't perform any value category conversions. In particular, an
   // identity conversion shouldn't change the expression category.
   if (target.kind == ConversionTarget::ExplicitAs) {

+ 4 - 2
toolchain/check/testdata/array/array_in_place.carbon

@@ -29,6 +29,7 @@ fn G() {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %.loc10_25: (type, type, type) = tuple_literal (i32, i32, i32)
 // CHECK:STDOUT:   %.loc10_28: i32 = int_literal 2
+// CHECK:STDOUT:   %.loc7: type = converted %.loc10_25, constants.%.loc7_25.2
 // CHECK:STDOUT:   %.loc10_29: type = array_type %.loc10_28, (i32, i32, i32)
 // CHECK:STDOUT:   %v.var: ref [(i32, i32, i32); 2] = var v
 // CHECK:STDOUT:   %v: ref [(i32, i32, i32); 2] = bind_name v, %v.var
@@ -45,7 +46,8 @@ fn G() {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc10_40: init (i32, i32, i32) = call %F.ref.loc10_39() to %.loc10_42.6
 // CHECK:STDOUT:   %.loc10_42.7: ((i32, i32, i32), (i32, i32, i32)) = tuple_literal (%.loc10_35, %.loc10_40)
-// CHECK:STDOUT:   %.loc10_42.8: init [(i32, i32, i32); 2] = array_init %.loc10_42.7, (%.loc10_35, %.loc10_40) to %v.var
-// CHECK:STDOUT:   assign %v.var, %.loc10_42.8
+// CHECK:STDOUT:   %.loc10_42.8: init [(i32, i32, i32); 2] = array_init (%.loc10_35, %.loc10_40) to %v.var
+// CHECK:STDOUT:   %.loc10_42.9: init [(i32, i32, i32); 2] = converted %.loc10_42.7, %.loc10_42.8
+// CHECK:STDOUT:   assign %v.var, %.loc10_42.9
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }

+ 6 - 4
toolchain/check/testdata/array/assign_return_value.carbon

@@ -25,8 +25,9 @@ fn Run() {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %.loc7_28: i32 = int_literal 0
 // CHECK:STDOUT:   %.loc7_30.1: (i32,) = tuple_literal (%.loc7_28)
-// CHECK:STDOUT:   %.loc7_30.2: (i32,) = tuple_value %.loc7_30.1, (%.loc7_28)
-// CHECK:STDOUT:   return %.loc7_30.2
+// CHECK:STDOUT:   %.loc7_30.2: (i32,) = tuple_value (%.loc7_28)
+// CHECK:STDOUT:   %.loc7_30.3: (i32,) = converted %.loc7_30.1, %.loc7_30.2
+// CHECK:STDOUT:   return %.loc7_30.3
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Run() {
@@ -44,7 +45,8 @@ fn Run() {
 // CHECK:STDOUT:   %.loc10_22.6: i32 = int_literal 0
 // CHECK:STDOUT:   %.loc10_22.7: ref i32 = array_index %t.var, %.loc10_22.6
 // CHECK:STDOUT:   %.loc10_22.8: init i32 = initialize_from %.loc10_22.5 to %.loc10_22.7
-// CHECK:STDOUT:   %.loc10_22.9: init [i32; 1] = array_init %.loc10_22.3, (%.loc10_22.8) to %t.var
-// CHECK:STDOUT:   assign %t.var, %.loc10_22.9
+// CHECK:STDOUT:   %.loc10_22.9: init [i32; 1] = array_init (%.loc10_22.8) to %t.var
+// CHECK:STDOUT:   %.loc10_22.10: init [i32; 1] = converted %.loc10_22.1, %.loc10_22.9
+// CHECK:STDOUT:   assign %t.var, %.loc10_22.10
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }

+ 8 - 5
toolchain/check/testdata/array/assign_var.carbon

@@ -15,7 +15,8 @@ var b: [i32; 3] = a;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file "assign_var.carbon" {
-// CHECK:STDOUT:   %.loc7_22: (type, type, type) = tuple_literal (i32, i32, i32)
+// CHECK:STDOUT:   %.loc7_22.1: (type, type, type) = tuple_literal (i32, i32, i32)
+// CHECK:STDOUT:   %.loc7_22.2: type = converted %.loc7_22.1, constants.%.loc7_22.2
 // CHECK:STDOUT:   %a.var: ref (i32, i32, i32) = var a
 // CHECK:STDOUT:   %a: ref (i32, i32, i32) = bind_name a, %a.var
 // CHECK:STDOUT:   %.loc7_27: i32 = int_literal 1
@@ -28,8 +29,9 @@ var b: [i32; 3] = a;
 // CHECK:STDOUT:   %.loc7_34.5: init i32 = initialize_from %.loc7_30 to %.loc7_34.4
 // CHECK:STDOUT:   %.loc7_34.6: ref i32 = tuple_access %a.var, member2
 // CHECK:STDOUT:   %.loc7_34.7: init i32 = initialize_from %.loc7_33 to %.loc7_34.6
-// CHECK:STDOUT:   %.loc7_34.8: init (i32, i32, i32) = tuple_init %.loc7_34.1, (%.loc7_34.3, %.loc7_34.5, %.loc7_34.7)
-// CHECK:STDOUT:   assign %a.var, %.loc7_34.8
+// CHECK:STDOUT:   %.loc7_34.8: init (i32, i32, i32) = tuple_init (%.loc7_34.3, %.loc7_34.5, %.loc7_34.7) to %a.var
+// CHECK:STDOUT:   %.loc7_34.9: init (i32, i32, i32) = converted %.loc7_34.1, %.loc7_34.8
+// CHECK:STDOUT:   assign %a.var, %.loc7_34.9
 // CHECK:STDOUT:   %.loc8_14: i32 = int_literal 3
 // CHECK:STDOUT:   %.loc8_15: type = array_type %.loc8_14, i32
 // CHECK:STDOUT:   %b.var: ref [i32; 3] = var b
@@ -50,6 +52,7 @@ var b: [i32; 3] = a;
 // CHECK:STDOUT:   %.loc8_19.13: i32 = int_literal 2
 // CHECK:STDOUT:   %.loc8_19.14: ref i32 = array_index %b.var, %.loc8_19.13
 // CHECK:STDOUT:   %.loc8_19.15: init i32 = initialize_from %.loc8_19.12 to %.loc8_19.14
-// CHECK:STDOUT:   %.loc8_19.16: init [i32; 3] = array_init %a.ref, (%.loc8_19.5, %.loc8_19.10, %.loc8_19.15) to %b.var
-// CHECK:STDOUT:   assign %b.var, %.loc8_19.16
+// CHECK:STDOUT:   %.loc8_19.16: init [i32; 3] = array_init (%.loc8_19.5, %.loc8_19.10, %.loc8_19.15) to %b.var
+// CHECK:STDOUT:   %.loc8_19.17: init [i32; 3] = converted %a.ref, %.loc8_19.16
+// CHECK:STDOUT:   assign %b.var, %.loc8_19.17
 // CHECK:STDOUT: }

+ 31 - 12
toolchain/check/testdata/array/base.carbon

@@ -28,8 +28,9 @@ var c: [(); 5] = ((), (), (), (), (),);
 // CHECK:STDOUT:   %.loc7_22.2: i32 = int_literal 0
 // CHECK:STDOUT:   %.loc7_22.3: ref i32 = array_index %a.var, %.loc7_22.2
 // CHECK:STDOUT:   %.loc7_22.4: init i32 = initialize_from %.loc7_20 to %.loc7_22.3
-// CHECK:STDOUT:   %.loc7_22.5: init [i32; 1] = array_init %.loc7_22.1, (%.loc7_22.4) to %a.var
-// CHECK:STDOUT:   assign %a.var, %.loc7_22.5
+// CHECK:STDOUT:   %.loc7_22.5: init [i32; 1] = array_init (%.loc7_22.4) to %a.var
+// CHECK:STDOUT:   %.loc7_22.6: init [i32; 1] = converted %.loc7_22.1, %.loc7_22.5
+// CHECK:STDOUT:   assign %a.var, %.loc7_22.6
 // CHECK:STDOUT:   %.loc8_14: i32 = int_literal 2
 // CHECK:STDOUT:   %.loc8_15: type = array_type %.loc8_14, f64
 // CHECK:STDOUT:   %b.var: ref [f64; 2] = var b
@@ -43,10 +44,12 @@ var c: [(); 5] = ((), (), (), (), (),);
 // CHECK:STDOUT:   %.loc8_30.5: i32 = int_literal 1
 // CHECK:STDOUT:   %.loc8_30.6: ref f64 = array_index %b.var, %.loc8_30.5
 // CHECK:STDOUT:   %.loc8_30.7: init f64 = initialize_from %.loc8_26 to %.loc8_30.6
-// CHECK:STDOUT:   %.loc8_30.8: init [f64; 2] = array_init %.loc8_30.1, (%.loc8_30.4, %.loc8_30.7) to %b.var
-// CHECK:STDOUT:   assign %b.var, %.loc8_30.8
-// CHECK:STDOUT:   %.loc9_10: () = tuple_literal ()
+// CHECK:STDOUT:   %.loc8_30.8: init [f64; 2] = array_init (%.loc8_30.4, %.loc8_30.7) to %b.var
+// CHECK:STDOUT:   %.loc8_30.9: init [f64; 2] = converted %.loc8_30.1, %.loc8_30.8
+// CHECK:STDOUT:   assign %b.var, %.loc8_30.9
+// CHECK:STDOUT:   %.loc9_10.1: () = tuple_literal ()
 // CHECK:STDOUT:   %.loc9_13: i32 = int_literal 5
+// CHECK:STDOUT:   %.loc9_10.2: type = converted %.loc9_10.1, constants.%.loc9_10
 // CHECK:STDOUT:   %.loc9_14: type = array_type %.loc9_13, ()
 // CHECK:STDOUT:   %c.var: ref [(); 5] = var c
 // CHECK:STDOUT:   %c: ref [(); 5] = bind_name c, %c.var
@@ -56,11 +59,27 @@ var c: [(); 5] = ((), (), (), (), (),);
 // CHECK:STDOUT:   %.loc9_32.1: () = tuple_literal ()
 // CHECK:STDOUT:   %.loc9_36.1: () = tuple_literal ()
 // CHECK:STDOUT:   %.loc9_38.1: ((), (), (), (), ()) = tuple_literal (%.loc9_20.1, %.loc9_24.1, %.loc9_28.1, %.loc9_32.1, %.loc9_36.1)
-// CHECK:STDOUT:   %.loc9_20.2: init () = tuple_init %.loc9_20.1, ()
-// CHECK:STDOUT:   %.loc9_24.2: init () = tuple_init %.loc9_24.1, ()
-// CHECK:STDOUT:   %.loc9_28.2: init () = tuple_init %.loc9_28.1, ()
-// CHECK:STDOUT:   %.loc9_32.2: init () = tuple_init %.loc9_32.1, ()
-// CHECK:STDOUT:   %.loc9_36.2: init () = tuple_init %.loc9_36.1, ()
-// CHECK:STDOUT:   %.loc9_38.2: init [(); 5] = array_init %.loc9_38.1, (%.loc9_20.2, %.loc9_24.2, %.loc9_28.2, %.loc9_32.2, %.loc9_36.2) to %c.var
-// CHECK:STDOUT:   assign %c.var, %.loc9_38.2
+// CHECK:STDOUT:   %.loc9_38.2: i32 = int_literal 0
+// CHECK:STDOUT:   %.loc9_38.3: ref () = array_index %c.var, %.loc9_38.2
+// CHECK:STDOUT:   %.loc9_20.2: init () = tuple_init () to %.loc9_38.3
+// CHECK:STDOUT:   %.loc9_20.3: init () = converted %.loc9_20.1, %.loc9_20.2
+// CHECK:STDOUT:   %.loc9_38.4: i32 = int_literal 1
+// CHECK:STDOUT:   %.loc9_38.5: ref () = array_index %c.var, %.loc9_38.4
+// CHECK:STDOUT:   %.loc9_24.2: init () = tuple_init () to %.loc9_38.5
+// CHECK:STDOUT:   %.loc9_24.3: init () = converted %.loc9_24.1, %.loc9_24.2
+// CHECK:STDOUT:   %.loc9_38.6: i32 = int_literal 2
+// CHECK:STDOUT:   %.loc9_38.7: ref () = array_index %c.var, %.loc9_38.6
+// CHECK:STDOUT:   %.loc9_28.2: init () = tuple_init () to %.loc9_38.7
+// CHECK:STDOUT:   %.loc9_28.3: init () = converted %.loc9_28.1, %.loc9_28.2
+// CHECK:STDOUT:   %.loc9_38.8: i32 = int_literal 3
+// CHECK:STDOUT:   %.loc9_38.9: ref () = array_index %c.var, %.loc9_38.8
+// CHECK:STDOUT:   %.loc9_32.2: init () = tuple_init () to %.loc9_38.9
+// CHECK:STDOUT:   %.loc9_32.3: init () = converted %.loc9_32.1, %.loc9_32.2
+// CHECK:STDOUT:   %.loc9_38.10: i32 = int_literal 4
+// CHECK:STDOUT:   %.loc9_38.11: ref () = array_index %c.var, %.loc9_38.10
+// CHECK:STDOUT:   %.loc9_36.2: init () = tuple_init () to %.loc9_38.11
+// CHECK:STDOUT:   %.loc9_36.3: init () = converted %.loc9_36.1, %.loc9_36.2
+// CHECK:STDOUT:   %.loc9_38.12: init [(); 5] = array_init (%.loc9_20.3, %.loc9_24.3, %.loc9_28.3, %.loc9_32.3, %.loc9_36.3) to %c.var
+// CHECK:STDOUT:   %.loc9_38.13: init [(); 5] = converted %.loc9_38.1, %.loc9_38.12
+// CHECK:STDOUT:   assign %c.var, %.loc9_38.13
 // CHECK:STDOUT: }

+ 3 - 1
toolchain/check/testdata/array/fail_type_mismatch.carbon

@@ -52,6 +52,7 @@ var d: [i32; 3] = t2;
 // CHECK:STDOUT:   %.loc10_39.4: init i32 = initialize_from %.loc10_20 to %.loc10_39.3
 // CHECK:STDOUT:   assign %a.var, <error>
 // CHECK:STDOUT:   %.loc12: (type, type, type) = tuple_literal (i32, String, String)
+// CHECK:STDOUT:   %.loc10_39.5: type = converted %.loc12, constants.%.loc10_39.1
 // CHECK:STDOUT:   %t1.var: ref (i32, String, String) = var t1
 // CHECK:STDOUT:   %t1: ref (i32, String, String) = bind_name t1, %t1.var
 // CHECK:STDOUT:   %.loc16_14: i32 = int_literal 3
@@ -72,9 +73,10 @@ var d: [i32; 3] = t2;
 // CHECK:STDOUT:   %c: ref [i32; 3] = bind_name c, %c.var
 // CHECK:STDOUT:   %.loc21_20: i32 = int_literal 1
 // CHECK:STDOUT:   %.loc21_23: i32 = int_literal 2
-// CHECK:STDOUT:   %.loc21_24: (i32, i32) = tuple_literal (%.loc21_20, %.loc21_23)
+// CHECK:STDOUT:   %.loc21_24.1: (i32, i32) = tuple_literal (%.loc21_20, %.loc21_23)
 // CHECK:STDOUT:   assign %c.var, <error>
 // CHECK:STDOUT:   %.loc23: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc21_24.2: type = converted %.loc23, constants.%.loc21_24.1
 // CHECK:STDOUT:   %t2.var: ref (i32, i32) = var t2
 // CHECK:STDOUT:   %t2: ref (i32, i32) = bind_name t2, %t2.var
 // CHECK:STDOUT:   %.loc27_14: i32 = int_literal 3

+ 8 - 6
toolchain/check/testdata/array/function_param.carbon

@@ -50,10 +50,12 @@ fn G() -> i32 {
 // CHECK:STDOUT:   %.loc12_20.9: i32 = int_literal 2
 // CHECK:STDOUT:   %.loc12_20.10: ref i32 = array_index %.loc12_20.2, %.loc12_20.9
 // CHECK:STDOUT:   %.loc12_20.11: init i32 = initialize_from %.loc12_19 to %.loc12_20.10
-// CHECK:STDOUT:   %.loc12_20.12: init [i32; 3] = array_init %.loc12_20.1, (%.loc12_20.5, %.loc12_20.8, %.loc12_20.11) to %.loc12_20.2
-// CHECK:STDOUT:   %.loc12_20.13: ref [i32; 3] = temporary %.loc12_20.2, %.loc12_20.12
-// CHECK:STDOUT:   %.loc12_20.14: [i32; 3] = bind_value %.loc12_20.13
-// CHECK:STDOUT:   %.loc12_11: init i32 = call %F.ref(%.loc12_20.14, %.loc12_23)
-// CHECK:STDOUT:   %.loc12_25: i32 = value_of_initializer %.loc12_11
-// CHECK:STDOUT:   return %.loc12_25
+// CHECK:STDOUT:   %.loc12_20.12: init [i32; 3] = array_init (%.loc12_20.5, %.loc12_20.8, %.loc12_20.11) to %.loc12_20.2
+// CHECK:STDOUT:   %.loc12_20.13: init [i32; 3] = converted %.loc12_20.1, %.loc12_20.12
+// CHECK:STDOUT:   %.loc12_20.14: ref [i32; 3] = temporary %.loc12_20.2, %.loc12_20.13
+// CHECK:STDOUT:   %.loc12_20.15: [i32; 3] = bind_value %.loc12_20.14
+// CHECK:STDOUT:   %.loc12_11: init i32 = call %F.ref(%.loc12_20.15, %.loc12_23)
+// CHECK:STDOUT:   %.loc12_25.1: i32 = value_of_initializer %.loc12_11
+// CHECK:STDOUT:   %.loc12_25.2: i32 = converted %.loc12_11, %.loc12_25.1
+// CHECK:STDOUT:   return %.loc12_25.2
 // CHECK:STDOUT: }

+ 3 - 2
toolchain/check/testdata/array/nine_elements.carbon

@@ -53,6 +53,7 @@ var a: [i32; 9] = (1, 2, 3, 4, 5, 6, 7, 8, 9);
 // CHECK:STDOUT:   %.loc7_45.26: i32 = int_literal 8
 // CHECK:STDOUT:   %.loc7_45.27: ref i32 = array_index %a.var, %.loc7_45.26
 // CHECK:STDOUT:   %.loc7_45.28: init i32 = initialize_from %.loc7_44 to %.loc7_45.27
-// CHECK:STDOUT:   %.loc7_45.29: init [i32; 9] = array_init %.loc7_45.1, (%.loc7_45.4, %.loc7_45.7, %.loc7_45.10, %.loc7_45.13, %.loc7_45.16, %.loc7_45.19, %.loc7_45.22, %.loc7_45.25, %.loc7_45.28) to %a.var
-// CHECK:STDOUT:   assign %a.var, %.loc7_45.29
+// CHECK:STDOUT:   %.loc7_45.29: init [i32; 9] = array_init (%.loc7_45.4, %.loc7_45.7, %.loc7_45.10, %.loc7_45.13, %.loc7_45.16, %.loc7_45.19, %.loc7_45.22, %.loc7_45.25, %.loc7_45.28) to %a.var
+// CHECK:STDOUT:   %.loc7_45.30: init [i32; 9] = converted %.loc7_45.1, %.loc7_45.29
+// CHECK:STDOUT:   assign %a.var, %.loc7_45.30
 // CHECK:STDOUT: }

+ 3 - 2
toolchain/check/testdata/as/as_type.carbon

@@ -12,6 +12,7 @@ let t: type = (i32, i32) as type;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file "as_type.carbon" {
-// CHECK:STDOUT:   %.loc7: (type, type) = tuple_literal (i32, i32)
-// CHECK:STDOUT:   %t: type = bind_name t, constants.%.loc7_26
+// CHECK:STDOUT:   %.loc7_24: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc7_26: type = converted %.loc7_24, constants.%.loc7_26
+// CHECK:STDOUT:   %t: type = bind_name t, %.loc7_26
 // CHECK:STDOUT: }

+ 3 - 1
toolchain/check/testdata/as/fail_no_conversion.carbon

@@ -16,8 +16,10 @@ let n: (i32, i32) = 1 as (i32, i32);
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file "fail_no_conversion.carbon" {
-// CHECK:STDOUT:   %.loc10_17: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc10_17.1: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc10_17.2: type = converted %.loc10_17.1, constants.%.loc10_17.2
 // CHECK:STDOUT:   %.loc10_21: i32 = int_literal 1
 // CHECK:STDOUT:   %.loc10_35: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc10_17.3: type = converted %.loc10_35, constants.%.loc10_17.2
 // CHECK:STDOUT:   %n: (i32, i32) = bind_name n, <error>
 // CHECK:STDOUT: }

+ 11 - 5
toolchain/check/testdata/as/tuple.carbon

@@ -49,7 +49,8 @@ fn Var() {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %X.ref.loc15_11: type = name_reference X, file.%X
 // CHECK:STDOUT:   %X.ref.loc15_14: type = name_reference X, file.%X
-// CHECK:STDOUT:   %.loc15_15: (type, type) = tuple_literal (%X.ref.loc15_11, %X.ref.loc15_14)
+// CHECK:STDOUT:   %.loc15_15.1: (type, type) = tuple_literal (%X.ref.loc15_11, %X.ref.loc15_14)
+// CHECK:STDOUT:   %.loc15_15.2: type = converted %.loc15_15.1, constants.%.loc15_15.2
 // CHECK:STDOUT:   %Make.ref.loc15_20: <function> = name_reference Make, file.%Make
 // CHECK:STDOUT:   %.loc15_24.1: ref X = temporary_storage
 // CHECK:STDOUT:   %.loc15_24.2: init X = call %Make.ref.loc15_20() to %.loc15_24.1
@@ -60,12 +61,14 @@ fn Var() {
 // CHECK:STDOUT:   %X.ref.loc15_40: type = name_reference X, file.%X
 // CHECK:STDOUT:   %X.ref.loc15_43: type = name_reference X, file.%X
 // CHECK:STDOUT:   %.loc15_44: (type, type) = tuple_literal (%X.ref.loc15_40, %X.ref.loc15_43)
+// CHECK:STDOUT:   %.loc15_15.3: type = converted %.loc15_44, constants.%.loc15_15.2
 // CHECK:STDOUT:   %.loc15_24.3: ref X = temporary %.loc15_24.1, %.loc15_24.2
 // CHECK:STDOUT:   %.loc15_24.4: X = bind_value %.loc15_24.3
 // CHECK:STDOUT:   %.loc15_32.3: ref X = temporary %.loc15_32.1, %.loc15_32.2
 // CHECK:STDOUT:   %.loc15_32.4: X = bind_value %.loc15_32.3
-// CHECK:STDOUT:   %.loc15_34.2: (X, X) = tuple_value %.loc15_34.1, (%.loc15_24.4, %.loc15_32.4)
-// CHECK:STDOUT:   %a: (X, X) = bind_name a, %.loc15_34.2
+// CHECK:STDOUT:   %.loc15_34.2: (X, X) = tuple_value (%.loc15_24.4, %.loc15_32.4)
+// CHECK:STDOUT:   %.loc15_34.3: (X, X) = converted %.loc15_34.1, %.loc15_34.2
+// CHECK:STDOUT:   %a: (X, X) = bind_name a, %.loc15_34.3
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -74,6 +77,7 @@ fn Var() {
 // CHECK:STDOUT:   %X.ref.loc20_11: type = name_reference X, file.%X
 // CHECK:STDOUT:   %X.ref.loc20_14: type = name_reference X, file.%X
 // CHECK:STDOUT:   %.loc20_15: (type, type) = tuple_literal (%X.ref.loc20_11, %X.ref.loc20_14)
+// CHECK:STDOUT:   %.loc15_15.1: type = converted %.loc20_15, constants.%.loc15_15.2
 // CHECK:STDOUT:   %b.var: ref (X, X) = var b
 // CHECK:STDOUT:   %b: ref (X, X) = bind_name b, %b.var
 // CHECK:STDOUT:   %Make.ref.loc20_20: <function> = name_reference Make, file.%Make
@@ -86,7 +90,9 @@ fn Var() {
 // CHECK:STDOUT:   %X.ref.loc20_40: type = name_reference X, file.%X
 // CHECK:STDOUT:   %X.ref.loc20_43: type = name_reference X, file.%X
 // CHECK:STDOUT:   %.loc20_44: (type, type) = tuple_literal (%X.ref.loc20_40, %X.ref.loc20_43)
-// CHECK:STDOUT:   %.loc20_34.4: init (X, X) = tuple_init %.loc20_34.3, (%.loc20_24, %.loc20_32)
-// CHECK:STDOUT:   assign %b.var, %.loc20_34.4
+// CHECK:STDOUT:   %.loc15_15.2: type = converted %.loc20_44, constants.%.loc15_15.2
+// CHECK:STDOUT:   %.loc20_34.4: init (X, X) = tuple_init (%.loc20_24, %.loc20_32) to %b.var
+// CHECK:STDOUT:   %.loc20_34.5: init (X, X) = converted %.loc20_34.3, %.loc20_34.4
+// CHECK:STDOUT:   assign %b.var, %.loc20_34.5
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }

+ 6 - 4
toolchain/check/testdata/basics/numeric_literals.carbon

@@ -63,8 +63,9 @@ fn F() {
 // CHECK:STDOUT:   %.loc16_3.14: i32 = int_literal 4
 // CHECK:STDOUT:   %.loc16_3.15: ref i32 = array_index %ints.var, %.loc16_3.14
 // CHECK:STDOUT:   %.loc16_3.16: init i32 = initialize_from %.loc15 to %.loc16_3.15
-// CHECK:STDOUT:   %.loc16_3.17: init [i32; 5] = array_init %.loc16_3.1, (%.loc16_3.4, %.loc16_3.7, %.loc16_3.10, %.loc16_3.13, %.loc16_3.16) to %ints.var
-// CHECK:STDOUT:   assign %ints.var, %.loc16_3.17
+// CHECK:STDOUT:   %.loc16_3.17: init [i32; 5] = array_init (%.loc16_3.4, %.loc16_3.7, %.loc16_3.10, %.loc16_3.13, %.loc16_3.16) to %ints.var
+// CHECK:STDOUT:   %.loc16_3.18: init [i32; 5] = converted %.loc16_3.1, %.loc16_3.17
+// CHECK:STDOUT:   assign %ints.var, %.loc16_3.18
 // CHECK:STDOUT:   %.loc17_21: i32 = int_literal 7
 // CHECK:STDOUT:   %.loc17_22: type = array_type %.loc17_21, f64
 // CHECK:STDOUT:   %floats.var: ref [f64; 7] = var floats
@@ -98,7 +99,8 @@ fn F() {
 // CHECK:STDOUT:   %.loc25_3.20: i32 = int_literal 6
 // CHECK:STDOUT:   %.loc25_3.21: ref f64 = array_index %floats.var, %.loc25_3.20
 // CHECK:STDOUT:   %.loc25_3.22: init f64 = initialize_from %.loc24 to %.loc25_3.21
-// CHECK:STDOUT:   %.loc25_3.23: init [f64; 7] = array_init %.loc25_3.1, (%.loc25_3.4, %.loc25_3.7, %.loc25_3.10, %.loc25_3.13, %.loc25_3.16, %.loc25_3.19, %.loc25_3.22) to %floats.var
-// CHECK:STDOUT:   assign %floats.var, %.loc25_3.23
+// CHECK:STDOUT:   %.loc25_3.23: init [f64; 7] = array_init (%.loc25_3.4, %.loc25_3.7, %.loc25_3.10, %.loc25_3.13, %.loc25_3.16, %.loc25_3.19, %.loc25_3.22) to %floats.var
+// CHECK:STDOUT:   %.loc25_3.24: init [f64; 7] = converted %.loc25_3.1, %.loc25_3.23
+// CHECK:STDOUT:   assign %floats.var, %.loc25_3.24
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }

+ 39 - 34
toolchain/check/testdata/basics/raw_and_textual_ir.carbon

@@ -17,14 +17,14 @@ fn Foo(n: i32) -> (i32, f64) {
 // CHECK:STDOUT: sem_ir:
 // CHECK:STDOUT:   cross_reference_irs_size: 1
 // CHECK:STDOUT:   functions:
-// CHECK:STDOUT:     function0:       {name: name0, param_refs: block1, return_type: type3, return_slot: inst+4, body: [block4]}
+// CHECK:STDOUT:     function0:       {name: name0, param_refs: block1, return_type: type3, return_slot: inst+5, body: [block4]}
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   types:
 // CHECK:STDOUT:     type0:           {inst: instIntegerType, value_rep: {kind: copy, type: type0}}
 // CHECK:STDOUT:     type1:           {inst: inst+1, value_rep: {kind: unknown, type: type<invalid>}}
 // CHECK:STDOUT:     type2:           {inst: instFloatingPointType, value_rep: {kind: copy, type: type2}}
 // CHECK:STDOUT:     type3:           {inst: inst+3, value_rep: {kind: pointer, type: type4}}
-// CHECK:STDOUT:     type4:           {inst: inst+5, value_rep: {kind: copy, type: type4}}
+// CHECK:STDOUT:     type4:           {inst: inst+6, value_rep: {kind: copy, type: type4}}
 // CHECK:STDOUT:     type5:           {inst: instFunctionType, value_rep: {kind: copy, type: type5}}
 // CHECK:STDOUT:   type_blocks:
 // CHECK:STDOUT:     typeBlock0:
@@ -38,20 +38,22 @@ fn Foo(n: i32) -> (i32, f64) {
 // CHECK:STDOUT:     inst+1:          {kind: TupleType, arg0: typeBlock0, type: typeTypeType}
 // CHECK:STDOUT:     inst+2:          {kind: TupleLiteral, arg0: block2, type: type1}
 // CHECK:STDOUT:     inst+3:          {kind: TupleType, arg0: typeBlock1, type: typeTypeType}
-// CHECK:STDOUT:     inst+4:          {kind: VarStorage, arg0: nameReturnSlot, type: type3}
-// CHECK:STDOUT:     inst+5:          {kind: PointerType, arg0: type3, type: typeTypeType}
-// CHECK:STDOUT:     inst+6:          {kind: FunctionDeclaration, arg0: function0, type: type5}
-// CHECK:STDOUT:     inst+7:          {kind: NameReference, arg0: name1, arg1: inst+0, type: type0}
-// CHECK:STDOUT:     inst+8:          {kind: IntegerLiteral, arg0: int3, type: type0}
-// CHECK:STDOUT:     inst+9:          {kind: BinaryOperatorAdd, arg0: inst+7, arg1: inst+8, type: type0}
-// CHECK:STDOUT:     inst+10:         {kind: RealLiteral, arg0: real0, type: type2}
-// CHECK:STDOUT:     inst+11:         {kind: TupleLiteral, arg0: block5, type: type3}
-// CHECK:STDOUT:     inst+12:         {kind: TupleAccess, arg0: inst+4, arg1: member0, type: type0}
-// CHECK:STDOUT:     inst+13:         {kind: InitializeFrom, arg0: inst+9, arg1: inst+12, type: type0}
-// CHECK:STDOUT:     inst+14:         {kind: TupleAccess, arg0: inst+4, arg1: member1, type: type2}
-// CHECK:STDOUT:     inst+15:         {kind: InitializeFrom, arg0: inst+10, arg1: inst+14, type: type2}
-// CHECK:STDOUT:     inst+16:         {kind: TupleInit, arg0: inst+11, arg1: block6, type: type3}
-// CHECK:STDOUT:     inst+17:         {kind: ReturnExpression, arg0: inst+16}
+// CHECK:STDOUT:     inst+4:          {kind: Converted, arg0: inst+2, arg1: inst+3, type: typeTypeType}
+// CHECK:STDOUT:     inst+5:          {kind: VarStorage, arg0: nameReturnSlot, type: type3}
+// CHECK:STDOUT:     inst+6:          {kind: PointerType, arg0: type3, type: typeTypeType}
+// CHECK:STDOUT:     inst+7:          {kind: FunctionDeclaration, arg0: function0, type: type5}
+// CHECK:STDOUT:     inst+8:          {kind: NameReference, arg0: name1, arg1: inst+0, type: type0}
+// CHECK:STDOUT:     inst+9:          {kind: IntegerLiteral, arg0: int3, type: type0}
+// CHECK:STDOUT:     inst+10:         {kind: BinaryOperatorAdd, arg0: inst+8, arg1: inst+9, type: type0}
+// CHECK:STDOUT:     inst+11:         {kind: RealLiteral, arg0: real0, type: type2}
+// CHECK:STDOUT:     inst+12:         {kind: TupleLiteral, arg0: block5, type: type3}
+// CHECK:STDOUT:     inst+13:         {kind: TupleAccess, arg0: inst+5, arg1: member0, type: type0}
+// CHECK:STDOUT:     inst+14:         {kind: InitializeFrom, arg0: inst+10, arg1: inst+13, type: type0}
+// CHECK:STDOUT:     inst+15:         {kind: TupleAccess, arg0: inst+5, arg1: member1, type: type2}
+// CHECK:STDOUT:     inst+16:         {kind: InitializeFrom, arg0: inst+11, arg1: inst+15, type: type2}
+// CHECK:STDOUT:     inst+17:         {kind: TupleInit, arg0: block6, arg1: inst+5, type: type3}
+// CHECK:STDOUT:     inst+18:         {kind: Converted, arg0: inst+12, arg1: inst+17, type: type3}
+// CHECK:STDOUT:     inst+19:         {kind: ReturnExpression, arg0: inst+18}
 // CHECK:STDOUT:   inst_blocks:
 // CHECK:STDOUT:     block0:          {}
 // CHECK:STDOUT:     block1:
@@ -63,26 +65,28 @@ fn Foo(n: i32) -> (i32, f64) {
 // CHECK:STDOUT:       0:               inst+0
 // CHECK:STDOUT:       1:               inst+2
 // CHECK:STDOUT:       2:               inst+4
+// CHECK:STDOUT:       3:               inst+5
 // CHECK:STDOUT:     block4:
-// CHECK:STDOUT:       0:               inst+7
-// CHECK:STDOUT:       1:               inst+8
-// CHECK:STDOUT:       2:               inst+9
-// CHECK:STDOUT:       3:               inst+10
-// CHECK:STDOUT:       4:               inst+11
-// CHECK:STDOUT:       5:               inst+12
-// CHECK:STDOUT:       6:               inst+13
-// CHECK:STDOUT:       7:               inst+14
-// CHECK:STDOUT:       8:               inst+15
-// CHECK:STDOUT:       9:               inst+16
-// CHECK:STDOUT:       10:              inst+17
+// CHECK:STDOUT:       0:               inst+8
+// CHECK:STDOUT:       1:               inst+9
+// CHECK:STDOUT:       2:               inst+10
+// CHECK:STDOUT:       3:               inst+11
+// CHECK:STDOUT:       4:               inst+12
+// CHECK:STDOUT:       5:               inst+13
+// CHECK:STDOUT:       6:               inst+14
+// CHECK:STDOUT:       7:               inst+15
+// CHECK:STDOUT:       8:               inst+16
+// CHECK:STDOUT:       9:               inst+17
+// CHECK:STDOUT:       10:              inst+18
+// CHECK:STDOUT:       11:              inst+19
 // CHECK:STDOUT:     block5:
-// CHECK:STDOUT:       0:               inst+9
-// CHECK:STDOUT:       1:               inst+10
+// CHECK:STDOUT:       0:               inst+10
+// CHECK:STDOUT:       1:               inst+11
 // CHECK:STDOUT:     block6:
-// CHECK:STDOUT:       0:               inst+13
-// CHECK:STDOUT:       1:               inst+15
+// CHECK:STDOUT:       0:               inst+14
+// CHECK:STDOUT:       1:               inst+16
 // CHECK:STDOUT:     block7:
-// CHECK:STDOUT:       0:               inst+6
+// CHECK:STDOUT:       0:               inst+7
 // CHECK:STDOUT: ...
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
@@ -106,6 +110,7 @@ fn Foo(n: i32) -> (i32, f64) {
 // CHECK:STDOUT:   %.loc12_21.3: init i32 = initialize_from %.loc12_13 to %.loc12_21.2
 // CHECK:STDOUT:   %.loc12_21.4: ref f64 = tuple_access %return, member1
 // CHECK:STDOUT:   %.loc12_21.5: init f64 = initialize_from %.loc12_18 to %.loc12_21.4
-// CHECK:STDOUT:   %.loc12_21.6: init (i32, f64) = tuple_init %.loc12_21.1, (%.loc12_21.3, %.loc12_21.5)
-// CHECK:STDOUT:   return %.loc12_21.6
+// CHECK:STDOUT:   %.loc12_21.6: init (i32, f64) = tuple_init (%.loc12_21.3, %.loc12_21.5) to %return
+// CHECK:STDOUT:   %.loc12_21.7: init (i32, f64) = converted %.loc12_21.1, %.loc12_21.6
+// CHECK:STDOUT:   return %.loc12_21.7
 // CHECK:STDOUT: }

+ 36 - 32
toolchain/check/testdata/basics/raw_ir.carbon

@@ -17,14 +17,14 @@ fn Foo(n: i32) -> (i32, f64) {
 // CHECK:STDOUT: sem_ir:
 // CHECK:STDOUT:   cross_reference_irs_size: 1
 // CHECK:STDOUT:   functions:
-// CHECK:STDOUT:     function0:       {name: name0, param_refs: block1, return_type: type3, return_slot: inst+4, body: [block4]}
+// CHECK:STDOUT:     function0:       {name: name0, param_refs: block1, return_type: type3, return_slot: inst+5, body: [block4]}
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   types:
 // CHECK:STDOUT:     type0:           {inst: instIntegerType, value_rep: {kind: copy, type: type0}}
 // CHECK:STDOUT:     type1:           {inst: inst+1, value_rep: {kind: unknown, type: type<invalid>}}
 // CHECK:STDOUT:     type2:           {inst: instFloatingPointType, value_rep: {kind: copy, type: type2}}
 // CHECK:STDOUT:     type3:           {inst: inst+3, value_rep: {kind: pointer, type: type4}}
-// CHECK:STDOUT:     type4:           {inst: inst+5, value_rep: {kind: copy, type: type4}}
+// CHECK:STDOUT:     type4:           {inst: inst+6, value_rep: {kind: copy, type: type4}}
 // CHECK:STDOUT:     type5:           {inst: instFunctionType, value_rep: {kind: copy, type: type5}}
 // CHECK:STDOUT:   type_blocks:
 // CHECK:STDOUT:     typeBlock0:
@@ -38,20 +38,22 @@ fn Foo(n: i32) -> (i32, f64) {
 // CHECK:STDOUT:     inst+1:          {kind: TupleType, arg0: typeBlock0, type: typeTypeType}
 // CHECK:STDOUT:     inst+2:          {kind: TupleLiteral, arg0: block2, type: type1}
 // CHECK:STDOUT:     inst+3:          {kind: TupleType, arg0: typeBlock1, type: typeTypeType}
-// CHECK:STDOUT:     inst+4:          {kind: VarStorage, arg0: nameReturnSlot, type: type3}
-// CHECK:STDOUT:     inst+5:          {kind: PointerType, arg0: type3, type: typeTypeType}
-// CHECK:STDOUT:     inst+6:          {kind: FunctionDeclaration, arg0: function0, type: type5}
-// CHECK:STDOUT:     inst+7:          {kind: NameReference, arg0: name1, arg1: inst+0, type: type0}
-// CHECK:STDOUT:     inst+8:          {kind: IntegerLiteral, arg0: int3, type: type0}
-// CHECK:STDOUT:     inst+9:          {kind: BinaryOperatorAdd, arg0: inst+7, arg1: inst+8, type: type0}
-// CHECK:STDOUT:     inst+10:         {kind: RealLiteral, arg0: real0, type: type2}
-// CHECK:STDOUT:     inst+11:         {kind: TupleLiteral, arg0: block5, type: type3}
-// CHECK:STDOUT:     inst+12:         {kind: TupleAccess, arg0: inst+4, arg1: member0, type: type0}
-// CHECK:STDOUT:     inst+13:         {kind: InitializeFrom, arg0: inst+9, arg1: inst+12, type: type0}
-// CHECK:STDOUT:     inst+14:         {kind: TupleAccess, arg0: inst+4, arg1: member1, type: type2}
-// CHECK:STDOUT:     inst+15:         {kind: InitializeFrom, arg0: inst+10, arg1: inst+14, type: type2}
-// CHECK:STDOUT:     inst+16:         {kind: TupleInit, arg0: inst+11, arg1: block6, type: type3}
-// CHECK:STDOUT:     inst+17:         {kind: ReturnExpression, arg0: inst+16}
+// CHECK:STDOUT:     inst+4:          {kind: Converted, arg0: inst+2, arg1: inst+3, type: typeTypeType}
+// CHECK:STDOUT:     inst+5:          {kind: VarStorage, arg0: nameReturnSlot, type: type3}
+// CHECK:STDOUT:     inst+6:          {kind: PointerType, arg0: type3, type: typeTypeType}
+// CHECK:STDOUT:     inst+7:          {kind: FunctionDeclaration, arg0: function0, type: type5}
+// CHECK:STDOUT:     inst+8:          {kind: NameReference, arg0: name1, arg1: inst+0, type: type0}
+// CHECK:STDOUT:     inst+9:          {kind: IntegerLiteral, arg0: int3, type: type0}
+// CHECK:STDOUT:     inst+10:         {kind: BinaryOperatorAdd, arg0: inst+8, arg1: inst+9, type: type0}
+// CHECK:STDOUT:     inst+11:         {kind: RealLiteral, arg0: real0, type: type2}
+// CHECK:STDOUT:     inst+12:         {kind: TupleLiteral, arg0: block5, type: type3}
+// CHECK:STDOUT:     inst+13:         {kind: TupleAccess, arg0: inst+5, arg1: member0, type: type0}
+// CHECK:STDOUT:     inst+14:         {kind: InitializeFrom, arg0: inst+10, arg1: inst+13, type: type0}
+// CHECK:STDOUT:     inst+15:         {kind: TupleAccess, arg0: inst+5, arg1: member1, type: type2}
+// CHECK:STDOUT:     inst+16:         {kind: InitializeFrom, arg0: inst+11, arg1: inst+15, type: type2}
+// CHECK:STDOUT:     inst+17:         {kind: TupleInit, arg0: block6, arg1: inst+5, type: type3}
+// CHECK:STDOUT:     inst+18:         {kind: Converted, arg0: inst+12, arg1: inst+17, type: type3}
+// CHECK:STDOUT:     inst+19:         {kind: ReturnExpression, arg0: inst+18}
 // CHECK:STDOUT:   inst_blocks:
 // CHECK:STDOUT:     block0:          {}
 // CHECK:STDOUT:     block1:
@@ -63,24 +65,26 @@ fn Foo(n: i32) -> (i32, f64) {
 // CHECK:STDOUT:       0:               inst+0
 // CHECK:STDOUT:       1:               inst+2
 // CHECK:STDOUT:       2:               inst+4
+// CHECK:STDOUT:       3:               inst+5
 // CHECK:STDOUT:     block4:
-// CHECK:STDOUT:       0:               inst+7
-// CHECK:STDOUT:       1:               inst+8
-// CHECK:STDOUT:       2:               inst+9
-// CHECK:STDOUT:       3:               inst+10
-// CHECK:STDOUT:       4:               inst+11
-// CHECK:STDOUT:       5:               inst+12
-// CHECK:STDOUT:       6:               inst+13
-// CHECK:STDOUT:       7:               inst+14
-// CHECK:STDOUT:       8:               inst+15
-// CHECK:STDOUT:       9:               inst+16
-// CHECK:STDOUT:       10:              inst+17
+// CHECK:STDOUT:       0:               inst+8
+// CHECK:STDOUT:       1:               inst+9
+// CHECK:STDOUT:       2:               inst+10
+// CHECK:STDOUT:       3:               inst+11
+// CHECK:STDOUT:       4:               inst+12
+// CHECK:STDOUT:       5:               inst+13
+// CHECK:STDOUT:       6:               inst+14
+// CHECK:STDOUT:       7:               inst+15
+// CHECK:STDOUT:       8:               inst+16
+// CHECK:STDOUT:       9:               inst+17
+// CHECK:STDOUT:       10:              inst+18
+// CHECK:STDOUT:       11:              inst+19
 // CHECK:STDOUT:     block5:
-// CHECK:STDOUT:       0:               inst+9
-// CHECK:STDOUT:       1:               inst+10
+// CHECK:STDOUT:       0:               inst+10
+// CHECK:STDOUT:       1:               inst+11
 // CHECK:STDOUT:     block6:
-// CHECK:STDOUT:       0:               inst+13
-// CHECK:STDOUT:       1:               inst+15
+// CHECK:STDOUT:       0:               inst+14
+// CHECK:STDOUT:       1:               inst+16
 // CHECK:STDOUT:     block7:
-// CHECK:STDOUT:       0:               inst+6
+// CHECK:STDOUT:       0:               inst+7
 // CHECK:STDOUT: ...

+ 3 - 2
toolchain/check/testdata/basics/textual_ir.carbon

@@ -33,6 +33,7 @@ fn Foo(n: i32) -> (i32, f64) {
 // CHECK:STDOUT:   %.loc12_21.3: init i32 = initialize_from %.loc12_13 to %.loc12_21.2
 // CHECK:STDOUT:   %.loc12_21.4: ref f64 = tuple_access %return, member1
 // CHECK:STDOUT:   %.loc12_21.5: init f64 = initialize_from %.loc12_18 to %.loc12_21.4
-// CHECK:STDOUT:   %.loc12_21.6: init (i32, f64) = tuple_init %.loc12_21.1, (%.loc12_21.3, %.loc12_21.5)
-// CHECK:STDOUT:   return %.loc12_21.6
+// CHECK:STDOUT:   %.loc12_21.6: init (i32, f64) = tuple_init (%.loc12_21.3, %.loc12_21.5) to %return
+// CHECK:STDOUT:   %.loc12_21.7: init (i32, f64) = converted %.loc12_21.1, %.loc12_21.6
+// CHECK:STDOUT:   return %.loc12_21.7
 // CHECK:STDOUT: }

+ 3 - 2
toolchain/check/testdata/class/basic.carbon

@@ -64,6 +64,7 @@ fn Run() -> i32 {
 // CHECK:STDOUT:   %F.ref: <function> = name_reference F, @Class.%F
 // CHECK:STDOUT:   %.loc22_18: i32 = int_literal 4
 // CHECK:STDOUT:   %.loc22_17: init i32 = call %F.ref(%.loc22_18)
-// CHECK:STDOUT:   %.loc22_20: i32 = value_of_initializer %.loc22_17
-// CHECK:STDOUT:   return %.loc22_20
+// CHECK:STDOUT:   %.loc22_20.1: i32 = value_of_initializer %.loc22_17
+// CHECK:STDOUT:   %.loc22_20.2: i32 = converted %.loc22_17, %.loc22_20.1
+// CHECK:STDOUT:   return %.loc22_20.2
 // CHECK:STDOUT: }

+ 3 - 0
toolchain/check/testdata/class/fail_init.carbon

@@ -58,6 +58,7 @@ fn F() {
 // CHECK:STDOUT:   %Class.ref.loc16: type = name_reference Class, file.%Class
 // CHECK:STDOUT:   %.loc16_10.2: ref Class = temporary_storage
 // CHECK:STDOUT:   %.loc16_10.3: ref Class = temporary %.loc16_10.2, <error>
+// CHECK:STDOUT:   %.loc16_10.4: ref Class = converted %.loc16_10.1, %.loc16_10.3
 // CHECK:STDOUT:   %.loc20_9: i32 = int_literal 1
 // CHECK:STDOUT:   %.loc20_17: i32 = int_literal 2
 // CHECK:STDOUT:   %.loc20_18.1: {.a: i32, .c: i32} = struct_literal (%.loc20_9, %.loc20_17)
@@ -66,6 +67,7 @@ fn F() {
 // CHECK:STDOUT:   %.loc20_18.3: ref i32 = class_field_access %.loc20_18.2, member0
 // CHECK:STDOUT:   %.loc20_18.4: init i32 = initialize_from %.loc20_9 to %.loc20_18.3
 // CHECK:STDOUT:   %.loc20_18.5: ref Class = temporary %.loc20_18.2, <error>
+// CHECK:STDOUT:   %.loc20_18.6: ref Class = converted %.loc20_18.1, %.loc20_18.5
 // CHECK:STDOUT:   %.loc24_9: i32 = int_literal 1
 // CHECK:STDOUT:   %.loc24_17: i32 = int_literal 2
 // CHECK:STDOUT:   %.loc24_25: i32 = int_literal 3
@@ -73,5 +75,6 @@ fn F() {
 // CHECK:STDOUT:   %Class.ref.loc24: type = name_reference Class, file.%Class
 // CHECK:STDOUT:   %.loc24_26.2: ref Class = temporary_storage
 // CHECK:STDOUT:   %.loc24_26.3: ref Class = temporary %.loc24_26.2, <error>
+// CHECK:STDOUT:   %.loc24_26.4: ref Class = converted %.loc24_26.1, %.loc24_26.3
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }

+ 3 - 2
toolchain/check/testdata/class/fail_init_as_inplace.carbon

@@ -64,9 +64,10 @@ fn F() {
 // CHECK:STDOUT:   %.loc21_33.4: init i32 = initialize_from %.loc21_24 to %.loc21_33.3
 // CHECK:STDOUT:   %.loc21_33.5: ref i32 = class_field_access %.loc21_33.2, member1
 // CHECK:STDOUT:   %.loc21_33.6: init i32 = initialize_from %.loc21_32 to %.loc21_33.5
-// CHECK:STDOUT:   %.loc21_33.7: init Class = class_init %.loc21_33.1, (%.loc21_33.4, %.loc21_33.6)
+// CHECK:STDOUT:   %.loc21_33.7: init Class = class_init (%.loc21_33.4, %.loc21_33.6), %.loc21_33.2
 // CHECK:STDOUT:   %.loc21_33.8: ref Class = temporary %.loc21_33.2, %.loc21_33.7
-// CHECK:STDOUT:   %.loc21_33.9: Class = bind_value %.loc21_33.8
+// CHECK:STDOUT:   %.loc21_33.9: ref Class = converted %.loc21_33.1, %.loc21_33.8
+// CHECK:STDOUT:   %.loc21_33.10: Class = bind_value %.loc21_33.9
 // CHECK:STDOUT:   assign %c.var, <error>
 // CHECK:STDOUT:   %G.ref: <function> = name_reference G, file.%G
 // CHECK:STDOUT:   %c.ref: ref Class = name_reference c, %c

+ 3 - 3
toolchain/check/testdata/class/fail_redeclaration_scope.carbon

@@ -40,7 +40,7 @@ class Y {
 // CHECK:STDOUT:   %B: type = class_type @B.2
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .B = <unexpected instref 20>
+// CHECK:STDOUT:   .B = <unexpected instref inst+11>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @X {
@@ -49,7 +49,7 @@ class Y {
 // CHECK:STDOUT:   class_declaration @B.1, ()
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .A = <unexpected instref 13>
+// CHECK:STDOUT:   .A = <unexpected instref inst+4>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @A.2 {
@@ -57,7 +57,7 @@ class Y {
 // CHECK:STDOUT:   %B: type = class_type @B.1
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .B = <unexpected instref 15>
+// CHECK:STDOUT:   .B = <unexpected instref inst+6>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @B.1 {

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

@@ -42,8 +42,8 @@ fn Class.H() {}
 // CHECK:STDOUT:   %H: <function> = fn_decl @H
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .F = <unexpected instref 11>
-// CHECK:STDOUT:   .H = <unexpected instref 12>
+// CHECK:STDOUT:   .F = <unexpected instref inst+2>
+// CHECK:STDOUT:   .H = <unexpected instref inst+3>
 // CHECK:STDOUT:   .G = %G
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 6 - 4
toolchain/check/testdata/class/init.carbon

@@ -54,8 +54,9 @@ fn MakeReorder(n: i32, next: Class*) -> Class {
 // CHECK:STDOUT:   %.loc13_31.3: init i32 = initialize_from %n.ref to %.loc13_31.2
 // CHECK:STDOUT:   %.loc13_31.4: ref Class* = class_field_access %return, member1
 // CHECK:STDOUT:   %.loc13_31.5: init Class* = initialize_from %next.ref to %.loc13_31.4
-// CHECK:STDOUT:   %.loc13_31.6: init Class = class_init %.loc13_31.1, (%.loc13_31.3, %.loc13_31.5)
-// CHECK:STDOUT:   return %.loc13_31.6
+// CHECK:STDOUT:   %.loc13_31.6: init Class = class_init (%.loc13_31.3, %.loc13_31.5), %return
+// CHECK:STDOUT:   %.loc13_31.7: init Class = converted %.loc13_31.1, %.loc13_31.6
+// CHECK:STDOUT:   return %.loc13_31.7
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @MakeReorder(%n: i32, %next: Class*) -> %return: Class {
@@ -67,6 +68,7 @@ fn MakeReorder(n: i32, next: Class*) -> Class {
 // CHECK:STDOUT:   %.loc17_31.3: init i32 = initialize_from %n.ref to %.loc17_31.2
 // CHECK:STDOUT:   %.loc17_31.4: ref Class* = class_field_access %return, member0
 // CHECK:STDOUT:   %.loc17_31.5: init Class* = initialize_from %next.ref to %.loc17_31.4
-// CHECK:STDOUT:   %.loc17_31.6: init Class = class_init %.loc17_31.1, (%.loc17_31.3, %.loc17_31.5)
-// CHECK:STDOUT:   return %.loc17_31.6
+// CHECK:STDOUT:   %.loc17_31.6: init Class = class_init (%.loc17_31.3, %.loc17_31.5), %return
+// CHECK:STDOUT:   %.loc17_31.7: init Class = converted %.loc17_31.1, %.loc17_31.6
+// CHECK:STDOUT:   return %.loc17_31.7
 // CHECK:STDOUT: }

+ 3 - 2
toolchain/check/testdata/class/init_as.carbon

@@ -48,9 +48,10 @@ fn F() -> i32 {
 // CHECK:STDOUT:   %.loc13_26.4: init i32 = initialize_from %.loc13_17 to %.loc13_26.3
 // CHECK:STDOUT:   %.loc13_26.5: ref i32 = class_field_access %.loc13_26.2, member1
 // CHECK:STDOUT:   %.loc13_26.6: init i32 = initialize_from %.loc13_25 to %.loc13_26.5
-// CHECK:STDOUT:   %.loc13_26.7: init Class = class_init %.loc13_26.1, (%.loc13_26.4, %.loc13_26.6)
+// CHECK:STDOUT:   %.loc13_26.7: init Class = class_init (%.loc13_26.4, %.loc13_26.6), %.loc13_26.2
 // CHECK:STDOUT:   %.loc13_26.8: ref Class = temporary %.loc13_26.2, %.loc13_26.7
-// CHECK:STDOUT:   %.loc13_37.1: ref i32 = class_field_access %.loc13_26.8, member0
+// CHECK:STDOUT:   %.loc13_26.9: ref Class = converted %.loc13_26.1, %.loc13_26.8
+// CHECK:STDOUT:   %.loc13_37.1: ref i32 = class_field_access %.loc13_26.9, member0
 // CHECK:STDOUT:   %.loc13_37.2: i32 = bind_value %.loc13_37.1
 // CHECK:STDOUT:   return %.loc13_37.2
 // CHECK:STDOUT: }

+ 3 - 2
toolchain/check/testdata/class/init_nested.carbon

@@ -77,6 +77,7 @@ fn MakeOuter() -> Outer {
 // CHECK:STDOUT:   %.loc20_45.2: ref Inner = class_field_access %return, member1
 // CHECK:STDOUT:   %.loc20_43: init Inner = call %MakeInner.ref.loc20_34() to %.loc20_45.2
 // CHECK:STDOUT:   %.loc20_45.3: {.c: Inner, .d: Inner} = struct_literal (%.loc20_25, %.loc20_43)
-// CHECK:STDOUT:   %.loc20_45.4: init Outer = class_init %.loc20_45.3, (%.loc20_25, %.loc20_43)
-// CHECK:STDOUT:   return %.loc20_45.4
+// CHECK:STDOUT:   %.loc20_45.4: init Outer = class_init (%.loc20_25, %.loc20_43), %return
+// CHECK:STDOUT:   %.loc20_45.5: init Outer = converted %.loc20_45.3, %.loc20_45.4
+// CHECK:STDOUT:   return %.loc20_45.5
 // CHECK:STDOUT: }

+ 18 - 12
toolchain/check/testdata/class/method.carbon

@@ -90,8 +90,9 @@ fn CallGOnInitializingExpression() -> i32 {
 // CHECK:STDOUT:   %c.ref: Class = name_reference c, %c
 // CHECK:STDOUT:   %.loc21_11: <bound method> = bound_method %c.ref, @Class.%F
 // CHECK:STDOUT:   %.loc21_13: init i32 = call %.loc21_11(%c.ref)
-// CHECK:STDOUT:   %.loc21_15: i32 = value_of_initializer %.loc21_13
-// CHECK:STDOUT:   return %.loc21_15
+// CHECK:STDOUT:   %.loc21_15.1: i32 = value_of_initializer %.loc21_13
+// CHECK:STDOUT:   %.loc21_15.2: i32 = converted %.loc21_13, %.loc21_15.1
+// CHECK:STDOUT:   return %.loc21_15.2
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @CallWithAddr() -> i32 {
@@ -103,8 +104,9 @@ fn CallGOnInitializingExpression() -> i32 {
 // CHECK:STDOUT:   %.loc26_11: <bound method> = bound_method %c.ref, @Class.%G
 // CHECK:STDOUT:   %.loc26_10: Class* = address_of %c.ref
 // CHECK:STDOUT:   %.loc26_13: init i32 = call %.loc26_11(%.loc26_10)
-// CHECK:STDOUT:   %.loc26_15: i32 = value_of_initializer %.loc26_13
-// CHECK:STDOUT:   return %.loc26_15
+// CHECK:STDOUT:   %.loc26_15.1: i32 = value_of_initializer %.loc26_13
+// CHECK:STDOUT:   %.loc26_15.2: i32 = converted %.loc26_13, %.loc26_15.1
+// CHECK:STDOUT:   return %.loc26_15.2
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @CallFThroughPointer(%p: Class*) -> i32 {
@@ -114,8 +116,9 @@ fn CallGOnInitializingExpression() -> i32 {
 // CHECK:STDOUT:   %.loc30_14: <bound method> = bound_method %.loc30_11.1, @Class.%F
 // CHECK:STDOUT:   %.loc30_11.2: Class = bind_value %.loc30_11.1
 // CHECK:STDOUT:   %.loc30_16: init i32 = call %.loc30_14(%.loc30_11.2)
-// CHECK:STDOUT:   %.loc30_18: i32 = value_of_initializer %.loc30_16
-// CHECK:STDOUT:   return %.loc30_18
+// CHECK:STDOUT:   %.loc30_18.1: i32 = value_of_initializer %.loc30_16
+// CHECK:STDOUT:   %.loc30_18.2: i32 = converted %.loc30_16, %.loc30_18.1
+// CHECK:STDOUT:   return %.loc30_18.2
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @CallGThroughPointer(%p: Class*) -> i32 {
@@ -125,8 +128,9 @@ fn CallGOnInitializingExpression() -> i32 {
 // CHECK:STDOUT:   %.loc34_14: <bound method> = bound_method %.loc34_11.1, @Class.%G
 // CHECK:STDOUT:   %.loc34_11.2: Class* = address_of %.loc34_11.1
 // CHECK:STDOUT:   %.loc34_16: init i32 = call %.loc34_14(%.loc34_11.2)
-// CHECK:STDOUT:   %.loc34_18: i32 = value_of_initializer %.loc34_16
-// CHECK:STDOUT:   return %.loc34_18
+// CHECK:STDOUT:   %.loc34_18.1: i32 = value_of_initializer %.loc34_16
+// CHECK:STDOUT:   %.loc34_18.2: i32 = converted %.loc34_16, %.loc34_18.1
+// CHECK:STDOUT:   return %.loc34_18.2
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Make() -> %return: Class;
@@ -140,8 +144,9 @@ fn CallGOnInitializingExpression() -> i32 {
 // CHECK:STDOUT:   %.loc40_16: <bound method> = bound_method %.loc40_14.3, @Class.%F
 // CHECK:STDOUT:   %.loc40_14.4: Class = bind_value %.loc40_14.3
 // CHECK:STDOUT:   %.loc40_18: init i32 = call %.loc40_16(%.loc40_14.4)
-// CHECK:STDOUT:   %.loc40_20: i32 = value_of_initializer %.loc40_18
-// CHECK:STDOUT:   return %.loc40_20
+// CHECK:STDOUT:   %.loc40_20.1: i32 = value_of_initializer %.loc40_18
+// CHECK:STDOUT:   %.loc40_20.2: i32 = converted %.loc40_18, %.loc40_20.1
+// CHECK:STDOUT:   return %.loc40_20.2
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @CallGOnInitializingExpression() -> i32 {
@@ -153,6 +158,7 @@ fn CallGOnInitializingExpression() -> i32 {
 // CHECK:STDOUT:   %.loc44_16: <bound method> = bound_method %.loc44_14.3, @Class.%G
 // CHECK:STDOUT:   %.loc44_14.4: Class* = address_of %.loc44_14.3
 // CHECK:STDOUT:   %.loc44_18: init i32 = call %.loc44_16(%.loc44_14.4)
-// CHECK:STDOUT:   %.loc44_20: i32 = value_of_initializer %.loc44_18
-// CHECK:STDOUT:   return %.loc44_20
+// CHECK:STDOUT:   %.loc44_20.1: i32 = value_of_initializer %.loc44_18
+// CHECK:STDOUT:   %.loc44_20.2: i32 = converted %.loc44_18, %.loc44_20.1
+// CHECK:STDOUT:   return %.loc44_20.2
 // CHECK:STDOUT: }

+ 1 - 1
toolchain/check/testdata/class/nested.carbon

@@ -61,7 +61,7 @@ fn F(a: Outer*) {
 // CHECK:STDOUT:   %pi: <unbound field of class Outer> = bind_name pi, %.loc16_9.2
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Inner = <unexpected instref 11>
+// CHECK:STDOUT:   .Inner = <unexpected instref inst+2>
 // CHECK:STDOUT:   .po = %po
 // CHECK:STDOUT:   .qo = %qo
 // CHECK:STDOUT:   .pi = %pi

+ 1 - 1
toolchain/check/testdata/class/nested_name.carbon

@@ -38,7 +38,7 @@ fn G(o: Outer) {
 // CHECK:STDOUT:   %Inner: type = class_type @Inner
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Inner = <unexpected instref 11>
+// CHECK:STDOUT:   .Inner = <unexpected instref inst+2>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Inner {

+ 3 - 2
toolchain/check/testdata/class/reenter_scope.carbon

@@ -36,8 +36,9 @@ fn Class.F() -> i32 {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %G.ref: <function> = name_reference G, @Class.%G
 // CHECK:STDOUT:   %.loc13_11: init i32 = call %G.ref()
-// CHECK:STDOUT:   %.loc13_13: i32 = value_of_initializer %.loc13_11
-// CHECK:STDOUT:   return %.loc13_13
+// CHECK:STDOUT:   %.loc13_13.1: i32 = value_of_initializer %.loc13_11
+// CHECK:STDOUT:   %.loc13_13.2: i32 = converted %.loc13_11, %.loc13_13.1
+// CHECK:STDOUT:   return %.loc13_13.2
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @G() -> i32;

+ 7 - 4
toolchain/check/testdata/class/scope.carbon

@@ -52,8 +52,9 @@ fn Run() -> i32 {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %F.ref: <function> = name_reference F, @Class.%F
 // CHECK:STDOUT:   %.loc13_13: init i32 = call %F.ref()
-// CHECK:STDOUT:   %.loc13_15: i32 = value_of_initializer %.loc13_13
-// CHECK:STDOUT:   return %.loc13_15
+// CHECK:STDOUT:   %.loc13_15.1: i32 = value_of_initializer %.loc13_13
+// CHECK:STDOUT:   %.loc13_15.2: i32 = converted %.loc13_13, %.loc13_15.1
+// CHECK:STDOUT:   return %.loc13_15.2
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @F.2() -> i32 {
@@ -70,7 +71,9 @@ fn Run() -> i32 {
 // CHECK:STDOUT:   %F.ref.loc22_21: <function> = name_reference F, @Class.%F
 // CHECK:STDOUT:   %.loc22_23.1: init i32 = call %F.ref.loc22_21()
 // CHECK:STDOUT:   %.loc22_14.1: i32 = value_of_initializer %.loc22_11
+// CHECK:STDOUT:   %.loc22_14.2: i32 = converted %.loc22_11, %.loc22_14.1
 // CHECK:STDOUT:   %.loc22_23.2: i32 = value_of_initializer %.loc22_23.1
-// CHECK:STDOUT:   %.loc22_14.2: i32 = add %.loc22_14.1, %.loc22_23.2
-// CHECK:STDOUT:   return %.loc22_14.2
+// CHECK:STDOUT:   %.loc22_23.3: i32 = converted %.loc22_23.1, %.loc22_23.2
+// CHECK:STDOUT:   %.loc22_14.3: i32 = add %.loc22_14.2, %.loc22_23.3
+// CHECK:STDOUT:   return %.loc22_14.3
 // CHECK:STDOUT: }

+ 3 - 2
toolchain/check/testdata/class/self_type.carbon

@@ -49,6 +49,7 @@ fn Class.F[self: Class]() -> i32 {
 // CHECK:STDOUT:   %.loc16_19: <bound method> = bound_method %.loc16_11.1, @Class.%F
 // CHECK:STDOUT:   %.loc16_11.2: Class = bind_value %.loc16_11.1
 // CHECK:STDOUT:   %.loc16_21: init i32 = call %.loc16_19(%.loc16_11.2)
-// CHECK:STDOUT:   %.loc16_23: i32 = value_of_initializer %.loc16_21
-// CHECK:STDOUT:   return %.loc16_23
+// CHECK:STDOUT:   %.loc16_23.1: i32 = value_of_initializer %.loc16_21
+// CHECK:STDOUT:   %.loc16_23.2: i32 = converted %.loc16_21, %.loc16_23.1
+// CHECK:STDOUT:   return %.loc16_23.2
 // CHECK:STDOUT: }

+ 3 - 2
toolchain/check/testdata/class/static_method.carbon

@@ -42,6 +42,7 @@ fn Run() -> i32 {
 // CHECK:STDOUT:   %c.ref: ref Class = name_reference c, %c
 // CHECK:STDOUT:   %F.ref: <function> = name_reference F, @Class.%F
 // CHECK:STDOUT:   %.loc13_13: init i32 = call %F.ref()
-// CHECK:STDOUT:   %.loc13_15: i32 = value_of_initializer %.loc13_13
-// CHECK:STDOUT:   return %.loc13_15
+// CHECK:STDOUT:   %.loc13_15.1: i32 = value_of_initializer %.loc13_13
+// CHECK:STDOUT:   %.loc13_15.2: i32 = converted %.loc13_13, %.loc13_15.1
+// CHECK:STDOUT:   return %.loc13_15.2
 // CHECK:STDOUT: }

+ 1 - 0
toolchain/check/testdata/expression_category/in_place_tuple_initialization.carbon

@@ -33,6 +33,7 @@ fn H() -> i32 {
 // CHECK:STDOUT: fn @G() -> %return: (i32, i32) {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %.loc10_19: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc7: type = converted %.loc10_19, constants.%.loc7_20.2
 // CHECK:STDOUT:   %v.var: ref (i32, i32) = var v
 // CHECK:STDOUT:   %v: ref (i32, i32) = bind_name v, %v.var
 // CHECK:STDOUT:   %F.ref.loc10: <function> = name_reference F, file.%F

+ 3 - 2
toolchain/check/testdata/function/call/empty_struct.carbon

@@ -32,7 +32,8 @@ fn Main() {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %Echo.ref: <function> = name_reference Echo, file.%Echo
 // CHECK:STDOUT:   %.loc12_9.1: {} = struct_literal ()
-// CHECK:STDOUT:   %.loc12_9.2: {} = struct_value %.loc12_9.1, ()
-// CHECK:STDOUT:   %.loc12_7: init {} = call %Echo.ref(%.loc12_9.2)
+// CHECK:STDOUT:   %.loc12_9.2: {} = struct_value ()
+// CHECK:STDOUT:   %.loc12_9.3: {} = converted %.loc12_9.1, %.loc12_9.2
+// CHECK:STDOUT:   %.loc12_7: init {} = call %Echo.ref(%.loc12_9.3)
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }

+ 3 - 2
toolchain/check/testdata/function/call/empty_tuple.carbon

@@ -31,7 +31,8 @@ fn Main() {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %Echo.ref: <function> = name_reference Echo, file.%Echo
 // CHECK:STDOUT:   %.loc12_9.1: () = tuple_literal ()
-// CHECK:STDOUT:   %.loc12_9.2: () = tuple_value %.loc12_9.1, ()
-// CHECK:STDOUT:   %.loc12_7: init () = call %Echo.ref(%.loc12_9.2)
+// CHECK:STDOUT:   %.loc12_9.2: () = tuple_value ()
+// CHECK:STDOUT:   %.loc12_9.3: () = converted %.loc12_9.1, %.loc12_9.2
+// CHECK:STDOUT:   %.loc12_7: init () = call %Echo.ref(%.loc12_9.3)
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }

+ 2 - 1
toolchain/check/testdata/function/call/return_implicit.carbon

@@ -27,7 +27,8 @@ fn Main() {
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Main() {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %.loc11_11: () = tuple_literal ()
+// CHECK:STDOUT:   %.loc11_11.1: () = tuple_literal ()
+// CHECK:STDOUT:   %.loc11_11.2: type = converted %.loc11_11.1, constants.%.loc11
 // CHECK:STDOUT:   %b.var: ref () = var b
 // CHECK:STDOUT:   %b: ref () = bind_name b, %b.var
 // CHECK:STDOUT:   %MakeImplicitEmptyTuple.ref: <function> = name_reference MakeImplicitEmptyTuple, file.%MakeImplicitEmptyTuple

+ 10 - 6
toolchain/check/testdata/if_expression/constant_condition.carbon

@@ -43,13 +43,15 @@ fn G() -> i32 {
 // CHECK:STDOUT:   %A.ref: <function> = name_reference A, file.%A
 // CHECK:STDOUT:   %.loc11_24.1: init i32 = call %A.ref()
 // CHECK:STDOUT:   %.loc11_24.2: i32 = value_of_initializer %.loc11_24.1
-// CHECK:STDOUT:   br !if.expr.result(%.loc11_24.2)
+// CHECK:STDOUT:   %.loc11_24.3: i32 = converted %.loc11_24.1, %.loc11_24.2
+// CHECK:STDOUT:   br !if.expr.result(%.loc11_24.3)
 // CHECK:STDOUT:
 // CHECK:STDOUT: !if.expr.else:
 // CHECK:STDOUT:   %B.ref: <function> = name_reference B, file.%B
 // CHECK:STDOUT:   %.loc11_33: init i32 = call %B.ref()
-// CHECK:STDOUT:   %.loc11_27: i32 = value_of_initializer %.loc11_33
-// CHECK:STDOUT:   br !if.expr.result(%.loc11_27)
+// CHECK:STDOUT:   %.loc11_27.1: i32 = value_of_initializer %.loc11_33
+// CHECK:STDOUT:   %.loc11_27.2: i32 = converted %.loc11_33, %.loc11_27.1
+// CHECK:STDOUT:   br !if.expr.result(%.loc11_27.2)
 // CHECK:STDOUT:
 // CHECK:STDOUT: !if.expr.result:
 // CHECK:STDOUT:   %.loc11_10: i32 = block_arg !if.expr.result
@@ -65,13 +67,15 @@ fn G() -> i32 {
 // CHECK:STDOUT:   %A.ref: <function> = name_reference A, file.%A
 // CHECK:STDOUT:   %.loc15_25.1: init i32 = call %A.ref()
 // CHECK:STDOUT:   %.loc15_25.2: i32 = value_of_initializer %.loc15_25.1
-// CHECK:STDOUT:   br !if.expr.result(%.loc15_25.2)
+// CHECK:STDOUT:   %.loc15_25.3: i32 = converted %.loc15_25.1, %.loc15_25.2
+// CHECK:STDOUT:   br !if.expr.result(%.loc15_25.3)
 // CHECK:STDOUT:
 // CHECK:STDOUT: !if.expr.else:
 // CHECK:STDOUT:   %B.ref: <function> = name_reference B, file.%B
 // CHECK:STDOUT:   %.loc15_34: init i32 = call %B.ref()
-// CHECK:STDOUT:   %.loc15_28: i32 = value_of_initializer %.loc15_34
-// CHECK:STDOUT:   br !if.expr.result(%.loc15_28)
+// CHECK:STDOUT:   %.loc15_28.1: i32 = value_of_initializer %.loc15_34
+// CHECK:STDOUT:   %.loc15_28.2: i32 = converted %.loc15_34, %.loc15_28.1
+// CHECK:STDOUT:   br !if.expr.result(%.loc15_28.2)
 // CHECK:STDOUT:
 // CHECK:STDOUT: !if.expr.result:
 // CHECK:STDOUT:   %.loc15_10: i32 = block_arg !if.expr.result

+ 5 - 3
toolchain/check/testdata/if_expression/control_flow.carbon

@@ -38,13 +38,15 @@ fn F(b: bool) -> i32 {
 // CHECK:STDOUT:   %A.ref: <function> = name_reference A, file.%A
 // CHECK:STDOUT:   %.loc11_21.1: init i32 = call %A.ref()
 // CHECK:STDOUT:   %.loc11_21.2: i32 = value_of_initializer %.loc11_21.1
-// CHECK:STDOUT:   br !if.expr.result(%.loc11_21.2)
+// CHECK:STDOUT:   %.loc11_21.3: i32 = converted %.loc11_21.1, %.loc11_21.2
+// CHECK:STDOUT:   br !if.expr.result(%.loc11_21.3)
 // CHECK:STDOUT:
 // CHECK:STDOUT: !if.expr.else:
 // CHECK:STDOUT:   %B.ref: <function> = name_reference B, file.%B
 // CHECK:STDOUT:   %.loc11_30: init i32 = call %B.ref()
-// CHECK:STDOUT:   %.loc11_24: i32 = value_of_initializer %.loc11_30
-// CHECK:STDOUT:   br !if.expr.result(%.loc11_24)
+// CHECK:STDOUT:   %.loc11_24.1: i32 = value_of_initializer %.loc11_30
+// CHECK:STDOUT:   %.loc11_24.2: i32 = converted %.loc11_30, %.loc11_24.1
+// CHECK:STDOUT:   br !if.expr.result(%.loc11_24.2)
 // CHECK:STDOUT:
 // CHECK:STDOUT: !if.expr.result:
 // CHECK:STDOUT:   %.loc11_10: i32 = block_arg !if.expr.result

+ 2 - 2
toolchain/check/testdata/if_expression/fail_not_in_function.carbon

@@ -38,7 +38,7 @@ class C {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file "fail_not_in_function.carbon" {
-// CHECK:STDOUT:   %.loc17: i32 = block_arg <unexpected instblockref 4>
+// CHECK:STDOUT:   %.loc17: i32 = block_arg <unexpected instblockref block4>
 // CHECK:STDOUT:   %x: i32 = bind_name x, %.loc17
 // CHECK:STDOUT:   class_declaration @C, ()
 // CHECK:STDOUT:   %C: type = class_type @C
@@ -49,5 +49,5 @@ class C {
 // CHECK:STDOUT:   if %.loc33 br !if.expr.then else br !if.expr.else
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .n = <unexpected instref 29>
+// CHECK:STDOUT:   .n = <unexpected instref inst+20>
 // CHECK:STDOUT: }

+ 9 - 6
toolchain/check/testdata/if_expression/struct.carbon

@@ -35,8 +35,9 @@ fn F(cond: bool) {
 // CHECK:STDOUT:   %.loc10_46.3: init i32 = initialize_from %.loc10_37 to %.loc10_46.2
 // CHECK:STDOUT:   %.loc10_46.4: ref i32 = struct_access %a.var, member1
 // CHECK:STDOUT:   %.loc10_46.5: init i32 = initialize_from %.loc10_45 to %.loc10_46.4
-// CHECK:STDOUT:   %.loc10_46.6: init {.a: i32, .b: i32} = struct_init %.loc10_46.1, (%.loc10_46.3, %.loc10_46.5)
-// CHECK:STDOUT:   assign %a.var, %.loc10_46.6
+// CHECK:STDOUT:   %.loc10_46.6: init {.a: i32, .b: i32} = struct_init (%.loc10_46.3, %.loc10_46.5) to %a.var
+// CHECK:STDOUT:   %.loc10_46.7: init {.a: i32, .b: i32} = converted %.loc10_46.1, %.loc10_46.6
+// CHECK:STDOUT:   assign %a.var, %.loc10_46.7
 // CHECK:STDOUT:   %G.ref: <function> = name_reference G, file.%G
 // CHECK:STDOUT:   %cond.ref: bool = name_reference cond, %cond
 // CHECK:STDOUT:   if %cond.ref br !if.expr.then else br !if.expr.else
@@ -47,8 +48,9 @@ fn F(cond: bool) {
 // CHECK:STDOUT:   %.loc11_18.2: i32 = bind_value %.loc11_18.1
 // CHECK:STDOUT:   %.loc11_18.3: ref i32 = struct_access %a.ref.loc11_18, member1
 // CHECK:STDOUT:   %.loc11_18.4: i32 = bind_value %.loc11_18.3
-// CHECK:STDOUT:   %.loc11_18.5: {.a: i32, .b: i32} = struct_value %a.ref.loc11_18, (%.loc11_18.2, %.loc11_18.4)
-// CHECK:STDOUT:   br !if.expr.result(%.loc11_18.5)
+// CHECK:STDOUT:   %.loc11_18.5: {.a: i32, .b: i32} = struct_value (%.loc11_18.2, %.loc11_18.4)
+// CHECK:STDOUT:   %.loc11_18.6: {.a: i32, .b: i32} = converted %a.ref.loc11_18, %.loc11_18.5
+// CHECK:STDOUT:   br !if.expr.result(%.loc11_18.6)
 // CHECK:STDOUT:
 // CHECK:STDOUT: !if.expr.else:
 // CHECK:STDOUT:   %a.ref.loc11_25: ref {.a: i32, .b: i32} = name_reference a, %a
@@ -56,8 +58,9 @@ fn F(cond: bool) {
 // CHECK:STDOUT:   %.loc11_25.2: i32 = bind_value %.loc11_25.1
 // CHECK:STDOUT:   %.loc11_25.3: ref i32 = struct_access %a.ref.loc11_25, member1
 // CHECK:STDOUT:   %.loc11_25.4: i32 = bind_value %.loc11_25.3
-// CHECK:STDOUT:   %.loc11_25.5: {.a: i32, .b: i32} = struct_value %a.ref.loc11_25, (%.loc11_25.2, %.loc11_25.4)
-// CHECK:STDOUT:   br !if.expr.result(%.loc11_25.5)
+// CHECK:STDOUT:   %.loc11_25.5: {.a: i32, .b: i32} = struct_value (%.loc11_25.2, %.loc11_25.4)
+// CHECK:STDOUT:   %.loc11_25.6: {.a: i32, .b: i32} = converted %a.ref.loc11_25, %.loc11_25.5
+// CHECK:STDOUT:   br !if.expr.result(%.loc11_25.6)
 // CHECK:STDOUT:
 // CHECK:STDOUT: !if.expr.result:
 // CHECK:STDOUT:   %.loc11_5: {.a: i32, .b: i32} = block_arg !if.expr.result

+ 3 - 2
toolchain/check/testdata/index/array_element_access.carbon

@@ -28,8 +28,9 @@ var d: i32 = a[b];
 // CHECK:STDOUT:   %.loc7_26.5: i32 = int_literal 1
 // CHECK:STDOUT:   %.loc7_26.6: ref i32 = array_index %a.var, %.loc7_26.5
 // CHECK:STDOUT:   %.loc7_26.7: init i32 = initialize_from %.loc7_24 to %.loc7_26.6
-// CHECK:STDOUT:   %.loc7_26.8: init [i32; 2] = array_init %.loc7_26.1, (%.loc7_26.4, %.loc7_26.7) to %a.var
-// CHECK:STDOUT:   assign %a.var, %.loc7_26.8
+// CHECK:STDOUT:   %.loc7_26.8: init [i32; 2] = array_init (%.loc7_26.4, %.loc7_26.7) to %a.var
+// CHECK:STDOUT:   %.loc7_26.9: init [i32; 2] = converted %.loc7_26.1, %.loc7_26.8
+// CHECK:STDOUT:   assign %a.var, %.loc7_26.9
 // CHECK:STDOUT:   %b.var: ref i32 = var b
 // CHECK:STDOUT:   %b: ref i32 = bind_name b, %b.var
 // CHECK:STDOUT:   %.loc8: i32 = int_literal 1

+ 6 - 4
toolchain/check/testdata/index/expression_category.carbon

@@ -56,8 +56,9 @@ fn ValueBinding(b: [i32; 3]) {
 // CHECK:STDOUT:   %.loc10_29.8: i32 = int_literal 2
 // CHECK:STDOUT:   %.loc10_29.9: ref i32 = array_index %a.var, %.loc10_29.8
 // CHECK:STDOUT:   %.loc10_29.10: init i32 = initialize_from %.loc10_28 to %.loc10_29.9
-// CHECK:STDOUT:   %.loc10_29.11: init [i32; 3] = array_init %.loc10_29.1, (%.loc10_29.4, %.loc10_29.7, %.loc10_29.10) to %a.var
-// CHECK:STDOUT:   assign %a.var, %.loc10_29.11
+// CHECK:STDOUT:   %.loc10_29.11: init [i32; 3] = array_init (%.loc10_29.4, %.loc10_29.7, %.loc10_29.10) to %a.var
+// CHECK:STDOUT:   %.loc10_29.12: init [i32; 3] = converted %.loc10_29.1, %.loc10_29.11
+// CHECK:STDOUT:   assign %a.var, %.loc10_29.12
 // CHECK:STDOUT:   %.loc13_14: type = ptr_type i32
 // CHECK:STDOUT:   %pa.var: ref i32* = var pa
 // CHECK:STDOUT:   %pa: ref i32* = bind_name pa, %pa.var
@@ -93,8 +94,9 @@ fn ValueBinding(b: [i32; 3]) {
 // CHECK:STDOUT:   %.loc18_29.8: i32 = int_literal 2
 // CHECK:STDOUT:   %.loc18_29.9: ref i32 = array_index %a.var, %.loc18_29.8
 // CHECK:STDOUT:   %.loc18_29.10: init i32 = initialize_from %.loc18_28 to %.loc18_29.9
-// CHECK:STDOUT:   %.loc18_29.11: init [i32; 3] = array_init %.loc18_29.1, (%.loc18_29.4, %.loc18_29.7, %.loc18_29.10) to %a.var
-// CHECK:STDOUT:   assign %a.var, %.loc18_29.11
+// CHECK:STDOUT:   %.loc18_29.11: init [i32; 3] = array_init (%.loc18_29.4, %.loc18_29.7, %.loc18_29.10) to %a.var
+// CHECK:STDOUT:   %.loc18_29.12: init [i32; 3] = converted %.loc18_29.1, %.loc18_29.11
+// CHECK:STDOUT:   assign %a.var, %.loc18_29.12
 // CHECK:STDOUT:   %a.ref: ref [i32; 3] = name_reference a, %a
 // CHECK:STDOUT:   %.loc22_5: i32 = int_literal 0
 // CHECK:STDOUT:   %.loc22_6: ref i32 = array_index %a.ref, %.loc22_5

+ 3 - 2
toolchain/check/testdata/index/fail_array_large_index.carbon

@@ -25,8 +25,9 @@ var b: i32 = a[0xFFFFFFFFFFFFFFFFF];
 // CHECK:STDOUT:   %.loc7_23.2: i32 = int_literal 0
 // CHECK:STDOUT:   %.loc7_23.3: ref i32 = array_index %a.var, %.loc7_23.2
 // CHECK:STDOUT:   %.loc7_23.4: init i32 = initialize_from %.loc7_20 to %.loc7_23.3
-// CHECK:STDOUT:   %.loc7_23.5: init [i32; 1] = array_init %.loc7_23.1, (%.loc7_23.4) to %a.var
-// CHECK:STDOUT:   assign %a.var, %.loc7_23.5
+// CHECK:STDOUT:   %.loc7_23.5: init [i32; 1] = array_init (%.loc7_23.4) to %a.var
+// CHECK:STDOUT:   %.loc7_23.6: init [i32; 1] = converted %.loc7_23.1, %.loc7_23.5
+// CHECK:STDOUT:   assign %a.var, %.loc7_23.6
 // CHECK:STDOUT:   %b.var: ref i32 = var b
 // CHECK:STDOUT:   %b: ref i32 = bind_name b, %b.var
 // CHECK:STDOUT:   %a.ref: ref [i32; 1] = name_reference a, %a

+ 3 - 2
toolchain/check/testdata/index/fail_array_non_int_indexing.carbon

@@ -25,8 +25,9 @@ var b: i32 = a[2.6];
 // CHECK:STDOUT:   %.loc7_23.2: i32 = int_literal 0
 // CHECK:STDOUT:   %.loc7_23.3: ref i32 = array_index %a.var, %.loc7_23.2
 // CHECK:STDOUT:   %.loc7_23.4: init i32 = initialize_from %.loc7_20 to %.loc7_23.3
-// CHECK:STDOUT:   %.loc7_23.5: init [i32; 1] = array_init %.loc7_23.1, (%.loc7_23.4) to %a.var
-// CHECK:STDOUT:   assign %a.var, %.loc7_23.5
+// CHECK:STDOUT:   %.loc7_23.5: init [i32; 1] = array_init (%.loc7_23.4) to %a.var
+// CHECK:STDOUT:   %.loc7_23.6: init [i32; 1] = converted %.loc7_23.1, %.loc7_23.5
+// CHECK:STDOUT:   assign %a.var, %.loc7_23.6
 // CHECK:STDOUT:   %b.var: ref i32 = var b
 // CHECK:STDOUT:   %b: ref i32 = bind_name b, %b.var
 // CHECK:STDOUT:   %a.ref: ref [i32; 1] = name_reference a, %a

+ 3 - 2
toolchain/check/testdata/index/fail_array_out_of_bound_access.carbon

@@ -25,8 +25,9 @@ var b: i32 = a[2];
 // CHECK:STDOUT:   %.loc7_23.2: i32 = int_literal 0
 // CHECK:STDOUT:   %.loc7_23.3: ref i32 = array_index %a.var, %.loc7_23.2
 // CHECK:STDOUT:   %.loc7_23.4: init i32 = initialize_from %.loc7_20 to %.loc7_23.3
-// CHECK:STDOUT:   %.loc7_23.5: init [i32; 1] = array_init %.loc7_23.1, (%.loc7_23.4) to %a.var
-// CHECK:STDOUT:   assign %a.var, %.loc7_23.5
+// CHECK:STDOUT:   %.loc7_23.5: init [i32; 1] = array_init (%.loc7_23.4) to %a.var
+// CHECK:STDOUT:   %.loc7_23.6: init [i32; 1] = converted %.loc7_23.1, %.loc7_23.5
+// CHECK:STDOUT:   assign %a.var, %.loc7_23.6
 // CHECK:STDOUT:   %b.var: ref i32 = var b
 // CHECK:STDOUT:   %b: ref i32 = bind_name b, %b.var
 // CHECK:STDOUT:   %a.ref: ref [i32; 1] = name_reference a, %a

+ 2 - 1
toolchain/check/testdata/index/fail_invalid_base.carbon

@@ -54,7 +54,8 @@ var d: i32 = {.a: i32, .b: i32}[0];
 // CHECK:STDOUT:   %.loc26_28: i32 = int_literal 2
 // CHECK:STDOUT:   %.loc26_29.1: {.a: i32, .b: i32} = struct_literal (%.loc26_20, %.loc26_28)
 // CHECK:STDOUT:   %.loc26_31: i32 = int_literal 0
-// CHECK:STDOUT:   %.loc26_29.2: {.a: i32, .b: i32} = struct_value %.loc26_29.1, (%.loc26_20, %.loc26_28)
+// CHECK:STDOUT:   %.loc26_29.2: {.a: i32, .b: i32} = struct_value (%.loc26_20, %.loc26_28)
+// CHECK:STDOUT:   %.loc26_29.3: {.a: i32, .b: i32} = converted %.loc26_29.1, %.loc26_29.2
 // CHECK:STDOUT:   assign %c.var, <error>
 // CHECK:STDOUT:   %d.var: ref i32 = var d
 // CHECK:STDOUT:   %d: ref i32 = bind_name d, %d.var

+ 5 - 3
toolchain/check/testdata/index/fail_non_deterministic_type.carbon

@@ -18,7 +18,8 @@ var c: i32 = a[b];
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file "fail_non_deterministic_type.carbon" {
-// CHECK:STDOUT:   %.loc7_17: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc7_17.1: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc7_17.2: type = converted %.loc7_17.1, constants.%.loc7_17.2
 // CHECK:STDOUT:   %a.var: ref (i32, i32) = var a
 // CHECK:STDOUT:   %a: ref (i32, i32) = bind_name a, %a.var
 // CHECK:STDOUT:   %.loc7_22: i32 = int_literal 2
@@ -28,8 +29,9 @@ var c: i32 = a[b];
 // CHECK:STDOUT:   %.loc7_26.3: init i32 = initialize_from %.loc7_22 to %.loc7_26.2
 // CHECK:STDOUT:   %.loc7_26.4: ref i32 = tuple_access %a.var, member1
 // CHECK:STDOUT:   %.loc7_26.5: init i32 = initialize_from %.loc7_25 to %.loc7_26.4
-// CHECK:STDOUT:   %.loc7_26.6: init (i32, i32) = tuple_init %.loc7_26.1, (%.loc7_26.3, %.loc7_26.5)
-// CHECK:STDOUT:   assign %a.var, %.loc7_26.6
+// CHECK:STDOUT:   %.loc7_26.6: init (i32, i32) = tuple_init (%.loc7_26.3, %.loc7_26.5) to %a.var
+// CHECK:STDOUT:   %.loc7_26.7: init (i32, i32) = converted %.loc7_26.1, %.loc7_26.6
+// CHECK:STDOUT:   assign %a.var, %.loc7_26.7
 // CHECK:STDOUT:   %b.var: ref i32 = var b
 // CHECK:STDOUT:   %b: ref i32 = bind_name b, %b.var
 // CHECK:STDOUT:   %.loc8: i32 = int_literal 0

+ 5 - 3
toolchain/check/testdata/index/fail_tuple_index_error.carbon

@@ -17,7 +17,8 @@ var b: i32 = a[oops];
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file "fail_tuple_index_error.carbon" {
-// CHECK:STDOUT:   %.loc7_17: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc7_17.1: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc7_17.2: type = converted %.loc7_17.1, constants.%.loc7_17.2
 // CHECK:STDOUT:   %a.var: ref (i32, i32) = var a
 // CHECK:STDOUT:   %a: ref (i32, i32) = bind_name a, %a.var
 // CHECK:STDOUT:   %.loc7_22: i32 = int_literal 12
@@ -27,8 +28,9 @@ var b: i32 = a[oops];
 // CHECK:STDOUT:   %.loc7_27.3: init i32 = initialize_from %.loc7_22 to %.loc7_27.2
 // CHECK:STDOUT:   %.loc7_27.4: ref i32 = tuple_access %a.var, member1
 // CHECK:STDOUT:   %.loc7_27.5: init i32 = initialize_from %.loc7_26 to %.loc7_27.4
-// CHECK:STDOUT:   %.loc7_27.6: init (i32, i32) = tuple_init %.loc7_27.1, (%.loc7_27.3, %.loc7_27.5)
-// CHECK:STDOUT:   assign %a.var, %.loc7_27.6
+// CHECK:STDOUT:   %.loc7_27.6: init (i32, i32) = tuple_init (%.loc7_27.3, %.loc7_27.5) to %a.var
+// CHECK:STDOUT:   %.loc7_27.7: init (i32, i32) = converted %.loc7_27.1, %.loc7_27.6
+// CHECK:STDOUT:   assign %a.var, %.loc7_27.7
 // CHECK:STDOUT:   %b.var: ref i32 = var b
 // CHECK:STDOUT:   %b: ref i32 = bind_name b, %b.var
 // CHECK:STDOUT:   %a.ref: ref (i32, i32) = name_reference a, %a

+ 9 - 5
toolchain/check/testdata/index/fail_tuple_large_index.carbon

@@ -17,21 +17,25 @@ var c: i32 = b[0xFFFFFFFFFFFFFFFFF];
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file "fail_tuple_large_index.carbon" {
-// CHECK:STDOUT:   %.loc7_13: (type,) = tuple_literal (i32)
+// CHECK:STDOUT:   %.loc7_13.1: (type,) = tuple_literal (i32)
+// CHECK:STDOUT:   %.loc7_13.2: type = converted %.loc7_13.1, constants.%.loc7_13.2
 // CHECK:STDOUT:   %a.var: ref (i32,) = var a
 // CHECK:STDOUT:   %a: ref (i32,) = bind_name a, %a.var
 // CHECK:STDOUT:   %.loc7_18: i32 = int_literal 12
 // CHECK:STDOUT:   %.loc7_21.1: (i32,) = tuple_literal (%.loc7_18)
-// CHECK:STDOUT:   %.loc7_21.2: init (i32,) = tuple_init %.loc7_21.1, (%.loc7_18)
-// CHECK:STDOUT:   assign %a.var, %.loc7_21.2
+// CHECK:STDOUT:   %.loc7_21.2: init (i32,) = tuple_init (%.loc7_18) to %a.var
+// CHECK:STDOUT:   %.loc7_21.3: init (i32,) = converted %.loc7_21.1, %.loc7_21.2
+// CHECK:STDOUT:   assign %a.var, %.loc7_21.3
 // CHECK:STDOUT:   %.loc8_13: (type,) = tuple_literal (i32)
+// CHECK:STDOUT:   %.loc7_13.3: type = converted %.loc8_13, constants.%.loc7_13.2
 // CHECK:STDOUT:   %b.var: ref (i32,) = var b
 // CHECK:STDOUT:   %b: ref (i32,) = bind_name b, %b.var
 // CHECK:STDOUT:   %a.ref: ref (i32,) = name_reference a, %a
 // CHECK:STDOUT:   %.loc8_17.1: ref i32 = tuple_access %a.ref, member0
 // CHECK:STDOUT:   %.loc8_17.2: i32 = bind_value %.loc8_17.1
-// CHECK:STDOUT:   %.loc8_17.3: init (i32,) = tuple_init %a.ref, (%.loc8_17.2)
-// CHECK:STDOUT:   assign %b.var, %.loc8_17.3
+// CHECK:STDOUT:   %.loc8_17.3: init (i32,) = tuple_init (%.loc8_17.2) to %b.var
+// CHECK:STDOUT:   %.loc8_17.4: init (i32,) = converted %a.ref, %.loc8_17.3
+// CHECK:STDOUT:   assign %b.var, %.loc8_17.4
 // CHECK:STDOUT:   %c.var: ref i32 = var c
 // CHECK:STDOUT:   %c: ref i32 = bind_name c, %c.var
 // CHECK:STDOUT:   %b.ref: ref (i32,) = name_reference b, %b

+ 5 - 3
toolchain/check/testdata/index/fail_tuple_non_int_indexing.carbon

@@ -17,7 +17,8 @@ var b: i32 = a[2.6];
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file "fail_tuple_non_int_indexing.carbon" {
-// CHECK:STDOUT:   %.loc7_17: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc7_17.1: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc7_17.2: type = converted %.loc7_17.1, constants.%.loc7_17.2
 // CHECK:STDOUT:   %a.var: ref (i32, i32) = var a
 // CHECK:STDOUT:   %a: ref (i32, i32) = bind_name a, %a.var
 // CHECK:STDOUT:   %.loc7_22: i32 = int_literal 12
@@ -27,8 +28,9 @@ var b: i32 = a[2.6];
 // CHECK:STDOUT:   %.loc7_27.3: init i32 = initialize_from %.loc7_22 to %.loc7_27.2
 // CHECK:STDOUT:   %.loc7_27.4: ref i32 = tuple_access %a.var, member1
 // CHECK:STDOUT:   %.loc7_27.5: init i32 = initialize_from %.loc7_26 to %.loc7_27.4
-// CHECK:STDOUT:   %.loc7_27.6: init (i32, i32) = tuple_init %.loc7_27.1, (%.loc7_27.3, %.loc7_27.5)
-// CHECK:STDOUT:   assign %a.var, %.loc7_27.6
+// CHECK:STDOUT:   %.loc7_27.6: init (i32, i32) = tuple_init (%.loc7_27.3, %.loc7_27.5) to %a.var
+// CHECK:STDOUT:   %.loc7_27.7: init (i32, i32) = converted %.loc7_27.1, %.loc7_27.6
+// CHECK:STDOUT:   assign %a.var, %.loc7_27.7
 // CHECK:STDOUT:   %b.var: ref i32 = var b
 // CHECK:STDOUT:   %b: ref i32 = bind_name b, %b.var
 // CHECK:STDOUT:   %a.ref: ref (i32, i32) = name_reference a, %a

+ 5 - 3
toolchain/check/testdata/index/fail_tuple_out_of_bound_access.carbon

@@ -17,7 +17,8 @@ var b: i32 = a[2];
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file "fail_tuple_out_of_bound_access.carbon" {
-// CHECK:STDOUT:   %.loc7_17: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc7_17.1: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc7_17.2: type = converted %.loc7_17.1, constants.%.loc7_17.2
 // CHECK:STDOUT:   %a.var: ref (i32, i32) = var a
 // CHECK:STDOUT:   %a: ref (i32, i32) = bind_name a, %a.var
 // CHECK:STDOUT:   %.loc7_22: i32 = int_literal 12
@@ -27,8 +28,9 @@ var b: i32 = a[2];
 // CHECK:STDOUT:   %.loc7_27.3: init i32 = initialize_from %.loc7_22 to %.loc7_27.2
 // CHECK:STDOUT:   %.loc7_27.4: ref i32 = tuple_access %a.var, member1
 // CHECK:STDOUT:   %.loc7_27.5: init i32 = initialize_from %.loc7_26 to %.loc7_27.4
-// CHECK:STDOUT:   %.loc7_27.6: init (i32, i32) = tuple_init %.loc7_27.1, (%.loc7_27.3, %.loc7_27.5)
-// CHECK:STDOUT:   assign %a.var, %.loc7_27.6
+// CHECK:STDOUT:   %.loc7_27.6: init (i32, i32) = tuple_init (%.loc7_27.3, %.loc7_27.5) to %a.var
+// CHECK:STDOUT:   %.loc7_27.7: init (i32, i32) = converted %.loc7_27.1, %.loc7_27.6
+// CHECK:STDOUT:   assign %a.var, %.loc7_27.7
 // CHECK:STDOUT:   %b.var: ref i32 = var b
 // CHECK:STDOUT:   %b: ref i32 = bind_name b, %b.var
 // CHECK:STDOUT:   %a.ref: ref (i32, i32) = name_reference a, %a

+ 9 - 5
toolchain/check/testdata/index/tuple_element_access.carbon

@@ -14,21 +14,25 @@ var c: i32 = b[0];
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file "tuple_element_access.carbon" {
-// CHECK:STDOUT:   %.loc7_13: (type,) = tuple_literal (i32)
+// CHECK:STDOUT:   %.loc7_13.1: (type,) = tuple_literal (i32)
+// CHECK:STDOUT:   %.loc7_13.2: type = converted %.loc7_13.1, constants.%.loc7_13.2
 // CHECK:STDOUT:   %a.var: ref (i32,) = var a
 // CHECK:STDOUT:   %a: ref (i32,) = bind_name a, %a.var
 // CHECK:STDOUT:   %.loc7_18: i32 = int_literal 12
 // CHECK:STDOUT:   %.loc7_21.1: (i32,) = tuple_literal (%.loc7_18)
-// CHECK:STDOUT:   %.loc7_21.2: init (i32,) = tuple_init %.loc7_21.1, (%.loc7_18)
-// CHECK:STDOUT:   assign %a.var, %.loc7_21.2
+// CHECK:STDOUT:   %.loc7_21.2: init (i32,) = tuple_init (%.loc7_18) to %a.var
+// CHECK:STDOUT:   %.loc7_21.3: init (i32,) = converted %.loc7_21.1, %.loc7_21.2
+// CHECK:STDOUT:   assign %a.var, %.loc7_21.3
 // CHECK:STDOUT:   %.loc8_13: (type,) = tuple_literal (i32)
+// CHECK:STDOUT:   %.loc7_13.3: type = converted %.loc8_13, constants.%.loc7_13.2
 // CHECK:STDOUT:   %b.var: ref (i32,) = var b
 // CHECK:STDOUT:   %b: ref (i32,) = bind_name b, %b.var
 // CHECK:STDOUT:   %a.ref: ref (i32,) = name_reference a, %a
 // CHECK:STDOUT:   %.loc8_17.1: ref i32 = tuple_access %a.ref, member0
 // CHECK:STDOUT:   %.loc8_17.2: i32 = bind_value %.loc8_17.1
-// CHECK:STDOUT:   %.loc8_17.3: init (i32,) = tuple_init %a.ref, (%.loc8_17.2)
-// CHECK:STDOUT:   assign %b.var, %.loc8_17.3
+// CHECK:STDOUT:   %.loc8_17.3: init (i32,) = tuple_init (%.loc8_17.2) to %b.var
+// CHECK:STDOUT:   %.loc8_17.4: init (i32,) = converted %a.ref, %.loc8_17.3
+// CHECK:STDOUT:   assign %b.var, %.loc8_17.4
 // CHECK:STDOUT:   %c.var: ref i32 = var c
 // CHECK:STDOUT:   %c: ref i32 = bind_name c, %c.var
 // CHECK:STDOUT:   %b.ref: ref (i32,) = name_reference b, %b

+ 3 - 2
toolchain/check/testdata/index/tuple_return_value_access.carbon

@@ -24,8 +24,9 @@ fn Run() -> i32 {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %.loc7_28: i32 = int_literal 0
 // CHECK:STDOUT:   %.loc7_30.1: (i32,) = tuple_literal (%.loc7_28)
-// CHECK:STDOUT:   %.loc7_30.2: (i32,) = tuple_value %.loc7_30.1, (%.loc7_28)
-// CHECK:STDOUT:   return %.loc7_30.2
+// CHECK:STDOUT:   %.loc7_30.2: (i32,) = tuple_value (%.loc7_28)
+// CHECK:STDOUT:   %.loc7_30.3: (i32,) = converted %.loc7_30.1, %.loc7_30.2
+// CHECK:STDOUT:   return %.loc7_30.3
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Run() -> i32 {

+ 9 - 5
toolchain/check/testdata/let/convert.carbon

@@ -23,7 +23,8 @@ fn F() -> i32 {
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @F() -> i32 {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %.loc8_24: (type, type, type) = tuple_literal (i32, i32, i32)
+// CHECK:STDOUT:   %.loc8_24.1: (type, type, type) = tuple_literal (i32, i32, i32)
+// CHECK:STDOUT:   %.loc8_24.2: type = converted %.loc8_24.1, constants.%.loc8_24.2
 // CHECK:STDOUT:   %v.var: ref (i32, i32, i32) = var v
 // CHECK:STDOUT:   %v: ref (i32, i32, i32) = bind_name v, %v.var
 // CHECK:STDOUT:   %.loc8_29: i32 = int_literal 1
@@ -36,9 +37,11 @@ fn F() -> i32 {
 // CHECK:STDOUT:   %.loc8_36.5: init i32 = initialize_from %.loc8_32 to %.loc8_36.4
 // CHECK:STDOUT:   %.loc8_36.6: ref i32 = tuple_access %v.var, member2
 // CHECK:STDOUT:   %.loc8_36.7: init i32 = initialize_from %.loc8_35 to %.loc8_36.6
-// CHECK:STDOUT:   %.loc8_36.8: init (i32, i32, i32) = tuple_init %.loc8_36.1, (%.loc8_36.3, %.loc8_36.5, %.loc8_36.7)
-// CHECK:STDOUT:   assign %v.var, %.loc8_36.8
+// CHECK:STDOUT:   %.loc8_36.8: init (i32, i32, i32) = tuple_init (%.loc8_36.3, %.loc8_36.5, %.loc8_36.7) to %v.var
+// CHECK:STDOUT:   %.loc8_36.9: init (i32, i32, i32) = converted %.loc8_36.1, %.loc8_36.8
+// CHECK:STDOUT:   assign %v.var, %.loc8_36.9
 // CHECK:STDOUT:   %.loc10_24: (type, type, type) = tuple_literal (i32, i32, i32)
+// CHECK:STDOUT:   %.loc8_24.3: type = converted %.loc10_24, constants.%.loc8_24.2
 // CHECK:STDOUT:   %v.ref: ref (i32, i32, i32) = name_reference v, %v
 // CHECK:STDOUT:   %.loc10_28.1: ref i32 = tuple_access %v.ref, member0
 // CHECK:STDOUT:   %.loc10_28.2: i32 = bind_value %.loc10_28.1
@@ -46,8 +49,9 @@ fn F() -> i32 {
 // CHECK:STDOUT:   %.loc10_28.4: i32 = bind_value %.loc10_28.3
 // CHECK:STDOUT:   %.loc10_28.5: ref i32 = tuple_access %v.ref, member2
 // CHECK:STDOUT:   %.loc10_28.6: i32 = bind_value %.loc10_28.5
-// CHECK:STDOUT:   %.loc10_28.7: (i32, i32, i32) = tuple_value %v.ref, (%.loc10_28.2, %.loc10_28.4, %.loc10_28.6)
-// CHECK:STDOUT:   %w: (i32, i32, i32) = bind_name w, %.loc10_28.7
+// CHECK:STDOUT:   %.loc10_28.7: (i32, i32, i32) = tuple_value (%.loc10_28.2, %.loc10_28.4, %.loc10_28.6)
+// CHECK:STDOUT:   %.loc10_28.8: (i32, i32, i32) = converted %v.ref, %.loc10_28.7
+// CHECK:STDOUT:   %w: (i32, i32, i32) = bind_name w, %.loc10_28.8
 // CHECK:STDOUT:   %w.ref: (i32, i32, i32) = name_reference w, %w
 // CHECK:STDOUT:   %.loc11_12: i32 = int_literal 1
 // CHECK:STDOUT:   %.loc11_13: i32 = tuple_index %w.ref, %.loc11_12

+ 8 - 6
toolchain/check/testdata/operators/and.carbon

@@ -34,16 +34,18 @@ fn And() -> bool {
 // CHECK:STDOUT:   %F.ref: <function> = name_reference F, file.%F
 // CHECK:STDOUT:   %.loc11_11: init bool = call %F.ref()
 // CHECK:STDOUT:   %.loc11_14.1: bool = value_of_initializer %.loc11_11
-// CHECK:STDOUT:   %.loc11_14.2: bool = bool_literal false
-// CHECK:STDOUT:   if %.loc11_14.1 br !and.rhs else br !and.result(%.loc11_14.2)
+// CHECK:STDOUT:   %.loc11_14.2: bool = converted %.loc11_11, %.loc11_14.1
+// CHECK:STDOUT:   %.loc11_14.3: bool = bool_literal false
+// CHECK:STDOUT:   if %.loc11_14.2 br !and.rhs else br !and.result(%.loc11_14.3)
 // CHECK:STDOUT:
 // CHECK:STDOUT: !and.rhs:
 // CHECK:STDOUT:   %G.ref: <function> = name_reference G, file.%G
 // CHECK:STDOUT:   %.loc11_19: init bool = call %G.ref()
-// CHECK:STDOUT:   %.loc11_14.3: bool = value_of_initializer %.loc11_19
-// CHECK:STDOUT:   br !and.result(%.loc11_14.3)
+// CHECK:STDOUT:   %.loc11_14.4: bool = value_of_initializer %.loc11_19
+// CHECK:STDOUT:   %.loc11_14.5: bool = converted %.loc11_19, %.loc11_14.4
+// CHECK:STDOUT:   br !and.result(%.loc11_14.5)
 // CHECK:STDOUT:
 // CHECK:STDOUT: !and.result:
-// CHECK:STDOUT:   %.loc11_14.4: bool = block_arg !and.result
-// CHECK:STDOUT:   return %.loc11_14.4
+// CHECK:STDOUT:   %.loc11_14.6: bool = block_arg !and.result
+// CHECK:STDOUT:   return %.loc11_14.6
 // CHECK:STDOUT: }

+ 8 - 5
toolchain/check/testdata/operators/assignment.carbon

@@ -42,7 +42,8 @@ fn Main() {
 // CHECK:STDOUT:   %a.ref.loc9: ref i32 = name_reference a, %a
 // CHECK:STDOUT:   %.loc9: i32 = int_literal 9
 // CHECK:STDOUT:   assign %a.ref.loc9, %.loc9
-// CHECK:STDOUT:   %.loc11_19: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc11_19.1: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc11_19.2: type = converted %.loc11_19.1, constants.%.loc11_19.2
 // CHECK:STDOUT:   %b.var: ref (i32, i32) = var b
 // CHECK:STDOUT:   %b: ref (i32, i32) = bind_name b, %b.var
 // CHECK:STDOUT:   %.loc11_24: i32 = int_literal 1
@@ -52,8 +53,9 @@ fn Main() {
 // CHECK:STDOUT:   %.loc11_28.3: init i32 = initialize_from %.loc11_24 to %.loc11_28.2
 // CHECK:STDOUT:   %.loc11_28.4: ref i32 = tuple_access %b.var, member1
 // CHECK:STDOUT:   %.loc11_28.5: init i32 = initialize_from %.loc11_27 to %.loc11_28.4
-// CHECK:STDOUT:   %.loc11_28.6: init (i32, i32) = tuple_init %.loc11_28.1, (%.loc11_28.3, %.loc11_28.5)
-// CHECK:STDOUT:   assign %b.var, %.loc11_28.6
+// CHECK:STDOUT:   %.loc11_28.6: init (i32, i32) = tuple_init (%.loc11_28.3, %.loc11_28.5) to %b.var
+// CHECK:STDOUT:   %.loc11_28.7: init (i32, i32) = converted %.loc11_28.1, %.loc11_28.6
+// CHECK:STDOUT:   assign %b.var, %.loc11_28.7
 // CHECK:STDOUT:   %b.ref.loc12: ref (i32, i32) = name_reference b, %b
 // CHECK:STDOUT:   %.loc12_5: i32 = int_literal 0
 // CHECK:STDOUT:   %.loc12_6: ref i32 = tuple_index %b.ref.loc12, %.loc12_5
@@ -74,8 +76,9 @@ fn Main() {
 // CHECK:STDOUT:   %.loc15_46.3: init i32 = initialize_from %.loc15_37 to %.loc15_46.2
 // CHECK:STDOUT:   %.loc15_46.4: ref i32 = struct_access %c.var, member1
 // CHECK:STDOUT:   %.loc15_46.5: init i32 = initialize_from %.loc15_45 to %.loc15_46.4
-// CHECK:STDOUT:   %.loc15_46.6: init {.a: i32, .b: i32} = struct_init %.loc15_46.1, (%.loc15_46.3, %.loc15_46.5)
-// CHECK:STDOUT:   assign %c.var, %.loc15_46.6
+// CHECK:STDOUT:   %.loc15_46.6: init {.a: i32, .b: i32} = struct_init (%.loc15_46.3, %.loc15_46.5) to %c.var
+// CHECK:STDOUT:   %.loc15_46.7: init {.a: i32, .b: i32} = converted %.loc15_46.1, %.loc15_46.6
+// CHECK:STDOUT:   assign %c.var, %.loc15_46.7
 // CHECK:STDOUT:   %c.ref.loc16: ref {.a: i32, .b: i32} = name_reference c, %c
 // CHECK:STDOUT:   %.loc16_4: ref i32 = struct_access %c.ref.loc16, member0
 // CHECK:STDOUT:   %.loc16_9: i32 = int_literal 3

+ 15 - 9
toolchain/check/testdata/operators/fail_assignment_to_non_assignable.carbon

@@ -78,9 +78,11 @@ fn Main() {
 // CHECK:STDOUT:   %.loc21_17.3: init i32 = initialize_from %.loc21_13 to %.loc21_17.2
 // CHECK:STDOUT:   %.loc21_17.4: i32 = tuple_access %.loc21_8.1, member1
 // CHECK:STDOUT:   %.loc21_17.5: init i32 = initialize_from %.loc21_16 to %.loc21_17.4
-// CHECK:STDOUT:   %.loc21_17.6: init (i32, i32) = tuple_init %.loc21_17.1, (%.loc21_17.3, %.loc21_17.5)
-// CHECK:STDOUT:   assign %.loc21_8.1, %.loc21_17.6
-// CHECK:STDOUT:   %.loc21_8.2: (i32, i32) = tuple_value %.loc21_8.1, (%.loc21_4, %.loc21_7)
+// CHECK:STDOUT:   %.loc21_17.6: init (i32, i32) = tuple_init (%.loc21_17.3, %.loc21_17.5) to %.loc21_8.1
+// CHECK:STDOUT:   %.loc21_17.7: init (i32, i32) = converted %.loc21_17.1, %.loc21_17.6
+// CHECK:STDOUT:   assign %.loc21_8.1, %.loc21_17.7
+// CHECK:STDOUT:   %.loc21_8.2: (i32, i32) = tuple_value (%.loc21_4, %.loc21_7)
+// CHECK:STDOUT:   %.loc21_8.3: (i32, i32) = converted %.loc21_8.1, %.loc21_8.2
 // CHECK:STDOUT:   %n.var: ref i32 = var n
 // CHECK:STDOUT:   %n: ref i32 = bind_name n, %n.var
 // CHECK:STDOUT:   %.loc22: i32 = int_literal 0
@@ -95,11 +97,13 @@ fn Main() {
 // CHECK:STDOUT:   %.loc26_17.3: init i32 = initialize_from %.loc26_13 to %.loc26_17.2
 // CHECK:STDOUT:   %.loc26_17.4: i32 = tuple_access %.loc26_8.1, member1
 // CHECK:STDOUT:   %.loc26_17.5: init i32 = initialize_from %.loc26_16 to %.loc26_17.4
-// CHECK:STDOUT:   %.loc26_17.6: init (i32, i32) = tuple_init %.loc26_17.1, (%.loc26_17.3, %.loc26_17.5)
-// CHECK:STDOUT:   assign %.loc26_8.1, %.loc26_17.6
+// CHECK:STDOUT:   %.loc26_17.6: init (i32, i32) = tuple_init (%.loc26_17.3, %.loc26_17.5) to %.loc26_8.1
+// CHECK:STDOUT:   %.loc26_17.7: init (i32, i32) = converted %.loc26_17.1, %.loc26_17.6
+// CHECK:STDOUT:   assign %.loc26_8.1, %.loc26_17.7
 // CHECK:STDOUT:   %.loc26_4: i32 = bind_value %n.ref.loc26_4
 // CHECK:STDOUT:   %.loc26_7: i32 = bind_value %n.ref.loc26_7
-// CHECK:STDOUT:   %.loc26_8.2: (i32, i32) = tuple_value %.loc26_8.1, (%.loc26_4, %.loc26_7)
+// CHECK:STDOUT:   %.loc26_8.2: (i32, i32) = tuple_value (%.loc26_4, %.loc26_7)
+// CHECK:STDOUT:   %.loc26_8.3: (i32, i32) = converted %.loc26_8.1, %.loc26_8.2
 // CHECK:STDOUT:   %.loc30: type = ptr_type i32
 // CHECK:STDOUT:   assign i32, %.loc30
 // CHECK:STDOUT:   %.loc34_9: i32 = int_literal 1
@@ -112,9 +116,11 @@ fn Main() {
 // CHECK:STDOUT:   %.loc34_37.3: init i32 = initialize_from %.loc34_28 to %.loc34_37.2
 // CHECK:STDOUT:   %.loc34_37.4: i32 = struct_access %.loc34_18.1, member1
 // CHECK:STDOUT:   %.loc34_37.5: init i32 = initialize_from %.loc34_36 to %.loc34_37.4
-// CHECK:STDOUT:   %.loc34_37.6: init {.x: i32, .y: i32} = struct_init %.loc34_37.1, (%.loc34_37.3, %.loc34_37.5)
-// CHECK:STDOUT:   assign %.loc34_18.1, %.loc34_37.6
-// CHECK:STDOUT:   %.loc34_18.2: {.x: i32, .y: i32} = struct_value %.loc34_18.1, (%.loc34_9, %.loc34_17)
+// CHECK:STDOUT:   %.loc34_37.6: init {.x: i32, .y: i32} = struct_init (%.loc34_37.3, %.loc34_37.5) to %.loc34_18.1
+// CHECK:STDOUT:   %.loc34_37.7: init {.x: i32, .y: i32} = converted %.loc34_37.1, %.loc34_37.6
+// CHECK:STDOUT:   assign %.loc34_18.1, %.loc34_37.7
+// CHECK:STDOUT:   %.loc34_18.2: {.x: i32, .y: i32} = struct_value (%.loc34_9, %.loc34_17)
+// CHECK:STDOUT:   %.loc34_18.3: {.x: i32, .y: i32} = converted %.loc34_18.1, %.loc34_18.2
 // CHECK:STDOUT:   %.loc38_7: bool = bool_literal true
 // CHECK:STDOUT:   if %.loc38_7 br !if.expr.then.loc38 else br !if.expr.else.loc38
 // CHECK:STDOUT:

+ 9 - 7
toolchain/check/testdata/operators/or.carbon

@@ -34,17 +34,19 @@ fn Or() -> bool {
 // CHECK:STDOUT:   %F.ref: <function> = name_reference F, file.%F
 // CHECK:STDOUT:   %.loc11_11: init bool = call %F.ref()
 // CHECK:STDOUT:   %.loc11_14.1: bool = value_of_initializer %.loc11_11
-// CHECK:STDOUT:   %.loc11_14.2: bool = not %.loc11_14.1
-// CHECK:STDOUT:   %.loc11_14.3: bool = bool_literal true
-// CHECK:STDOUT:   if %.loc11_14.2 br !or.rhs else br !or.result(%.loc11_14.3)
+// CHECK:STDOUT:   %.loc11_14.2: bool = converted %.loc11_11, %.loc11_14.1
+// CHECK:STDOUT:   %.loc11_14.3: bool = not %.loc11_14.2
+// CHECK:STDOUT:   %.loc11_14.4: bool = bool_literal true
+// CHECK:STDOUT:   if %.loc11_14.3 br !or.rhs else br !or.result(%.loc11_14.4)
 // CHECK:STDOUT:
 // CHECK:STDOUT: !or.rhs:
 // CHECK:STDOUT:   %G.ref: <function> = name_reference G, file.%G
 // CHECK:STDOUT:   %.loc11_18: init bool = call %G.ref()
-// CHECK:STDOUT:   %.loc11_14.4: bool = value_of_initializer %.loc11_18
-// CHECK:STDOUT:   br !or.result(%.loc11_14.4)
+// CHECK:STDOUT:   %.loc11_14.5: bool = value_of_initializer %.loc11_18
+// CHECK:STDOUT:   %.loc11_14.6: bool = converted %.loc11_18, %.loc11_14.5
+// CHECK:STDOUT:   br !or.result(%.loc11_14.6)
 // CHECK:STDOUT:
 // CHECK:STDOUT: !or.result:
-// CHECK:STDOUT:   %.loc11_14.5: bool = block_arg !or.result
-// CHECK:STDOUT:   return %.loc11_14.5
+// CHECK:STDOUT:   %.loc11_14.7: bool = block_arg !or.result
+// CHECK:STDOUT:   return %.loc11_14.7
 // CHECK:STDOUT: }

+ 8 - 5
toolchain/check/testdata/pointer/address_of_lvalue.carbon

@@ -39,8 +39,9 @@ fn F() {
 // CHECK:STDOUT:   %.loc8_46.3: init i32 = initialize_from %.loc8_37 to %.loc8_46.2
 // CHECK:STDOUT:   %.loc8_46.4: ref i32 = struct_access %s.var, member1
 // CHECK:STDOUT:   %.loc8_46.5: init i32 = initialize_from %.loc8_45 to %.loc8_46.4
-// CHECK:STDOUT:   %.loc8_46.6: init {.a: i32, .b: i32} = struct_init %.loc8_46.1, (%.loc8_46.3, %.loc8_46.5)
-// CHECK:STDOUT:   assign %s.var, %.loc8_46.6
+// CHECK:STDOUT:   %.loc8_46.6: init {.a: i32, .b: i32} = struct_init (%.loc8_46.3, %.loc8_46.5) to %s.var
+// CHECK:STDOUT:   %.loc8_46.7: init {.a: i32, .b: i32} = converted %.loc8_46.1, %.loc8_46.6
+// CHECK:STDOUT:   assign %s.var, %.loc8_46.7
 // CHECK:STDOUT:   %.loc10_27: type = struct_type {.a: i32, .b: i32}
 // CHECK:STDOUT:   %.loc10_28: type = ptr_type {.a: i32, .b: i32}
 // CHECK:STDOUT:   %p.var: ref {.a: i32, .b: i32}* = var p
@@ -62,7 +63,8 @@ fn F() {
 // CHECK:STDOUT:   %.loc12_19: ref i32 = struct_access %s.ref.loc12, member1
 // CHECK:STDOUT:   %.loc12_17: i32* = address_of %.loc12_19
 // CHECK:STDOUT:   assign %r.var, %.loc12_17
-// CHECK:STDOUT:   %.loc14_19: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc14_19.1: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc14_19.2: type = converted %.loc14_19.1, constants.%.loc14_19.2
 // CHECK:STDOUT:   %t.var: ref (i32, i32) = var t
 // CHECK:STDOUT:   %t: ref (i32, i32) = bind_name t, %t.var
 // CHECK:STDOUT:   %.loc14_24: i32 = int_literal 1
@@ -72,8 +74,9 @@ fn F() {
 // CHECK:STDOUT:   %.loc14_28.3: init i32 = initialize_from %.loc14_24 to %.loc14_28.2
 // CHECK:STDOUT:   %.loc14_28.4: ref i32 = tuple_access %t.var, member1
 // CHECK:STDOUT:   %.loc14_28.5: init i32 = initialize_from %.loc14_27 to %.loc14_28.4
-// CHECK:STDOUT:   %.loc14_28.6: init (i32, i32) = tuple_init %.loc14_28.1, (%.loc14_28.3, %.loc14_28.5)
-// CHECK:STDOUT:   assign %t.var, %.loc14_28.6
+// CHECK:STDOUT:   %.loc14_28.6: init (i32, i32) = tuple_init (%.loc14_28.3, %.loc14_28.5) to %t.var
+// CHECK:STDOUT:   %.loc14_28.7: init (i32, i32) = converted %.loc14_28.1, %.loc14_28.6
+// CHECK:STDOUT:   assign %t.var, %.loc14_28.7
 // CHECK:STDOUT:   %.loc15_14: type = ptr_type i32
 // CHECK:STDOUT:   %t0.var: ref i32* = var t0
 // CHECK:STDOUT:   %t0: ref i32* = bind_name t0, %t0.var

+ 3 - 2
toolchain/check/testdata/pointer/fail_address_of_value.carbon

@@ -169,8 +169,9 @@ fn AddressOfParameter(param: i32) {
 // CHECK:STDOUT:   %.loc75_9: i32 = int_literal 2
 // CHECK:STDOUT:   %.loc75_10.1: (i32, i32) = tuple_literal (%.loc75_6, %.loc75_9)
 // CHECK:STDOUT:   %.loc75_12: i32 = int_literal 0
-// CHECK:STDOUT:   %.loc75_10.2: (i32, i32) = tuple_value %.loc75_10.1, (%.loc75_6, %.loc75_9)
-// CHECK:STDOUT:   %.loc75_13: i32 = tuple_index %.loc75_10.2, %.loc75_12
+// CHECK:STDOUT:   %.loc75_10.2: (i32, i32) = tuple_value (%.loc75_6, %.loc75_9)
+// CHECK:STDOUT:   %.loc75_10.3: (i32, i32) = converted %.loc75_10.1, %.loc75_10.2
+// CHECK:STDOUT:   %.loc75_13: i32 = tuple_index %.loc75_10.3, %.loc75_12
 // CHECK:STDOUT:   %.loc75_3: i32* = address_of %.loc75_13
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }

+ 6 - 4
toolchain/check/testdata/pointer/fail_dereference_not_pointer.carbon

@@ -33,10 +33,12 @@ fn Deref(n: i32) {
 // CHECK:STDOUT:   %n.ref: i32 = name_reference n, %n
 // CHECK:STDOUT:   %.loc11: ref <error> = dereference %n.ref
 // CHECK:STDOUT:   %.loc15_5.1: () = tuple_literal ()
-// CHECK:STDOUT:   %.loc15_5.2: () = tuple_value %.loc15_5.1, ()
-// CHECK:STDOUT:   %.loc15_3: ref <error> = dereference %.loc15_5.2
+// CHECK:STDOUT:   %.loc15_5.2: () = tuple_value ()
+// CHECK:STDOUT:   %.loc15_5.3: () = converted %.loc15_5.1, %.loc15_5.2
+// CHECK:STDOUT:   %.loc15_3: ref <error> = dereference %.loc15_5.3
 // CHECK:STDOUT:   %.loc19_5.1: {} = struct_literal ()
-// CHECK:STDOUT:   %.loc19_5.2: {} = struct_value %.loc19_5.1, ()
-// CHECK:STDOUT:   %.loc19_3: ref <error> = dereference %.loc19_5.2
+// CHECK:STDOUT:   %.loc19_5.2: {} = struct_value ()
+// CHECK:STDOUT:   %.loc19_5.3: {} = converted %.loc19_5.1, %.loc19_5.2
+// CHECK:STDOUT:   %.loc19_3: ref <error> = dereference %.loc19_5.3
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }

+ 3 - 2
toolchain/check/testdata/return/struct.carbon

@@ -16,6 +16,7 @@ fn Main() -> {.a: i32} {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %.loc8_16: i32 = int_literal 3
 // CHECK:STDOUT:   %.loc8_17.1: {.a: i32} = struct_literal (%.loc8_16)
-// CHECK:STDOUT:   %.loc8_17.2: {.a: i32} = struct_value %.loc8_17.1, (%.loc8_16)
-// CHECK:STDOUT:   return %.loc8_17.2
+// CHECK:STDOUT:   %.loc8_17.2: {.a: i32} = struct_value (%.loc8_16)
+// CHECK:STDOUT:   %.loc8_17.3: {.a: i32} = converted %.loc8_17.1, %.loc8_17.2
+// CHECK:STDOUT:   return %.loc8_17.3
 // CHECK:STDOUT: }

+ 3 - 2
toolchain/check/testdata/return/tuple.carbon

@@ -28,6 +28,7 @@ fn Main() -> (i32, i32) {
 // CHECK:STDOUT:   %.loc9_17.3: init i32 = initialize_from %.loc9_11 to %.loc9_17.2
 // CHECK:STDOUT:   %.loc9_17.4: ref i32 = tuple_access %return, member1
 // CHECK:STDOUT:   %.loc9_17.5: init i32 = initialize_from %.loc9_15 to %.loc9_17.4
-// CHECK:STDOUT:   %.loc9_17.6: init (i32, i32) = tuple_init %.loc9_17.1, (%.loc9_17.3, %.loc9_17.5)
-// CHECK:STDOUT:   return %.loc9_17.6
+// CHECK:STDOUT:   %.loc9_17.6: init (i32, i32) = tuple_init (%.loc9_17.3, %.loc9_17.5) to %return
+// CHECK:STDOUT:   %.loc9_17.7: init (i32, i32) = converted %.loc9_17.1, %.loc9_17.6
+// CHECK:STDOUT:   return %.loc9_17.7
 // CHECK:STDOUT: }

+ 9 - 5
toolchain/check/testdata/struct/empty.carbon

@@ -13,16 +13,20 @@ var y: {} = x;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file "empty.carbon" {
-// CHECK:STDOUT:   %.loc7_9: {} = struct_literal ()
+// CHECK:STDOUT:   %.loc7_9.1: {} = struct_literal ()
+// CHECK:STDOUT:   %.loc7_9.2: type = converted %.loc7_9.1, constants.%.loc7_9.1
 // CHECK:STDOUT:   %x.var: ref {} = var x
 // CHECK:STDOUT:   %x: ref {} = bind_name x, %x.var
 // CHECK:STDOUT:   %.loc7_14.1: {} = struct_literal ()
-// CHECK:STDOUT:   %.loc7_14.2: init {} = struct_init %.loc7_14.1, ()
-// CHECK:STDOUT:   assign %x.var, %.loc7_14.2
+// CHECK:STDOUT:   %.loc7_14.2: init {} = struct_init () to %x.var
+// CHECK:STDOUT:   %.loc7_14.3: init {} = converted %.loc7_14.1, %.loc7_14.2
+// CHECK:STDOUT:   assign %x.var, %.loc7_14.3
 // CHECK:STDOUT:   %.loc8_9: {} = struct_literal ()
+// CHECK:STDOUT:   %.loc7_9.3: type = converted %.loc8_9, constants.%.loc7_9.1
 // CHECK:STDOUT:   %y.var: ref {} = var y
 // CHECK:STDOUT:   %y: ref {} = bind_name y, %y.var
 // CHECK:STDOUT:   %x.ref: ref {} = name_reference x, %x
-// CHECK:STDOUT:   %.loc8_13: init {} = struct_init %x.ref, ()
-// CHECK:STDOUT:   assign %y.var, %.loc8_13
+// CHECK:STDOUT:   %.loc8_13.1: init {} = struct_init () to %y.var
+// CHECK:STDOUT:   %.loc8_13.2: init {} = converted %x.ref, %.loc8_13.1
+// CHECK:STDOUT:   assign %y.var, %.loc8_13.2
 // CHECK:STDOUT: }

+ 2 - 1
toolchain/check/testdata/struct/fail_assign_nested.carbon

@@ -17,7 +17,8 @@ var x: {.a: {}} = {.b = {}};
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file "fail_assign_nested.carbon" {
-// CHECK:STDOUT:   %.loc10_14: {} = struct_literal ()
+// CHECK:STDOUT:   %.loc10_14.1: {} = struct_literal ()
+// CHECK:STDOUT:   %.loc10_14.2: type = converted %.loc10_14.1, constants.%.loc10_14.1
 // CHECK:STDOUT:   %.loc10_15: type = struct_type {.a: {}}
 // CHECK:STDOUT:   %x.var: ref {.a: {}} = var x
 // CHECK:STDOUT:   %x: ref {.a: {}} = bind_name x, %x.var

+ 2 - 1
toolchain/check/testdata/struct/fail_assign_to_empty.carbon

@@ -16,7 +16,8 @@ var x: {} = {.a = 1};
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file "fail_assign_to_empty.carbon" {
-// CHECK:STDOUT:   %.loc10_9: {} = struct_literal ()
+// CHECK:STDOUT:   %.loc10_9.1: {} = struct_literal ()
+// CHECK:STDOUT:   %.loc10_9.2: type = converted %.loc10_9.1, constants.%.loc10_9.1
 // CHECK:STDOUT:   %x.var: ref {} = var x
 // CHECK:STDOUT:   %x: ref {} = bind_name x, %x.var
 // CHECK:STDOUT:   %.loc10_19: i32 = int_literal 1

+ 3 - 2
toolchain/check/testdata/struct/fail_member_access_type.carbon

@@ -16,8 +16,9 @@ var y: i32 = x.b;
 // CHECK:STDOUT:   %x: ref {.a: f64} = bind_name x, %x.var
 // CHECK:STDOUT:   %.loc7_26: f64 = real_literal 40e-1
 // CHECK:STDOUT:   %.loc7_29.1: {.a: f64} = struct_literal (%.loc7_26)
-// CHECK:STDOUT:   %.loc7_29.2: init {.a: f64} = struct_init %.loc7_29.1, (%.loc7_26)
-// CHECK:STDOUT:   assign %x.var, %.loc7_29.2
+// CHECK:STDOUT:   %.loc7_29.2: init {.a: f64} = struct_init (%.loc7_26) to %x.var
+// CHECK:STDOUT:   %.loc7_29.3: init {.a: f64} = converted %.loc7_29.1, %.loc7_29.2
+// CHECK:STDOUT:   assign %x.var, %.loc7_29.3
 // CHECK:STDOUT:   %y.var: ref i32 = var y
 // CHECK:STDOUT:   %y: ref i32 = bind_name y, %y.var
 // CHECK:STDOUT:   %x.ref: ref {.a: f64} = name_reference x, %x

+ 3 - 2
toolchain/check/testdata/struct/fail_non_member_access.carbon

@@ -16,8 +16,9 @@ var y: i32 = x.b;
 // CHECK:STDOUT:   %x: ref {.a: i32} = bind_name x, %x.var
 // CHECK:STDOUT:   %.loc7_26: i32 = int_literal 4
 // CHECK:STDOUT:   %.loc7_27.1: {.a: i32} = struct_literal (%.loc7_26)
-// CHECK:STDOUT:   %.loc7_27.2: init {.a: i32} = struct_init %.loc7_27.1, (%.loc7_26)
-// CHECK:STDOUT:   assign %x.var, %.loc7_27.2
+// CHECK:STDOUT:   %.loc7_27.2: init {.a: i32} = struct_init (%.loc7_26) to %x.var
+// CHECK:STDOUT:   %.loc7_27.3: init {.a: i32} = converted %.loc7_27.1, %.loc7_27.2
+// CHECK:STDOUT:   assign %x.var, %.loc7_27.3
 // CHECK:STDOUT:   %y.var: ref i32 = var y
 // CHECK:STDOUT:   %y: ref i32 = bind_name y, %y.var
 // CHECK:STDOUT:   %x.ref: ref {.a: i32} = name_reference x, %x

+ 5 - 3
toolchain/check/testdata/struct/literal_member_access.carbon

@@ -39,9 +39,11 @@ fn F() -> i32 {
 // CHECK:STDOUT:   %.loc10_25.7: i32 = bind_value %.loc10_25.6
 // CHECK:STDOUT:   %.loc10_25.8: ref i32 = struct_access %.loc10_25.3, member2
 // CHECK:STDOUT:   %.loc10_25.9: i32 = bind_value %.loc10_25.8
-// CHECK:STDOUT:   %.loc10_25.10: {.x: i32, .y: i32, .z: i32} = struct_value %.loc10_25.3, (%.loc10_25.5, %.loc10_25.7, %.loc10_25.9)
-// CHECK:STDOUT:   %.loc10_35.2: {.a: i32, .b: {.x: i32, .y: i32, .z: i32}, .c: i32} = struct_value %.loc10_35.1, (%.loc10_16, %.loc10_25.10, %.loc10_34)
-// CHECK:STDOUT:   %.loc10_36: {.x: i32, .y: i32, .z: i32} = struct_access %.loc10_35.2, member1
+// CHECK:STDOUT:   %.loc10_25.10: {.x: i32, .y: i32, .z: i32} = struct_value (%.loc10_25.5, %.loc10_25.7, %.loc10_25.9)
+// CHECK:STDOUT:   %.loc10_25.11: {.x: i32, .y: i32, .z: i32} = converted %.loc10_25.2, %.loc10_25.10
+// CHECK:STDOUT:   %.loc10_35.2: {.a: i32, .b: {.x: i32, .y: i32, .z: i32}, .c: i32} = struct_value (%.loc10_16, %.loc10_25.11, %.loc10_34)
+// CHECK:STDOUT:   %.loc10_35.3: {.a: i32, .b: {.x: i32, .y: i32, .z: i32}, .c: i32} = converted %.loc10_35.1, %.loc10_35.2
+// CHECK:STDOUT:   %.loc10_36: {.x: i32, .y: i32, .z: i32} = struct_access %.loc10_35.3, member1
 // CHECK:STDOUT:   %.loc10_38: i32 = struct_access %.loc10_36, member1
 // CHECK:STDOUT:   return %.loc10_38
 // CHECK:STDOUT: }

+ 3 - 2
toolchain/check/testdata/struct/member_access.carbon

@@ -23,8 +23,9 @@ var z: i32 = y;
 // CHECK:STDOUT:   %.loc7_46.3: init f64 = initialize_from %.loc7_35 to %.loc7_46.2
 // CHECK:STDOUT:   %.loc7_46.4: ref i32 = struct_access %x.var, member1
 // CHECK:STDOUT:   %.loc7_46.5: init i32 = initialize_from %.loc7_45 to %.loc7_46.4
-// CHECK:STDOUT:   %.loc7_46.6: init {.a: f64, .b: i32} = struct_init %.loc7_46.1, (%.loc7_46.3, %.loc7_46.5)
-// CHECK:STDOUT:   assign %x.var, %.loc7_46.6
+// CHECK:STDOUT:   %.loc7_46.6: init {.a: f64, .b: i32} = struct_init (%.loc7_46.3, %.loc7_46.5) to %x.var
+// CHECK:STDOUT:   %.loc7_46.7: init {.a: f64, .b: i32} = converted %.loc7_46.1, %.loc7_46.6
+// CHECK:STDOUT:   assign %x.var, %.loc7_46.7
 // CHECK:STDOUT:   %y.var: ref i32 = var y
 // CHECK:STDOUT:   %y: ref i32 = bind_name y, %y.var
 // CHECK:STDOUT:   %x.ref: ref {.a: f64, .b: i32} = name_reference x, %x

+ 5 - 2
toolchain/check/testdata/struct/nested_struct_in_place.carbon

@@ -28,7 +28,9 @@ fn G() {
 // CHECK:STDOUT: fn @G() {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %.loc10_29: (type, type, type) = tuple_literal (i32, i32, i32)
+// CHECK:STDOUT:   %.loc7_25.1: type = converted %.loc10_29, constants.%.loc7_25.2
 // CHECK:STDOUT:   %.loc10_50: (type, type, type) = tuple_literal (i32, i32, i32)
+// CHECK:STDOUT:   %.loc7_25.2: type = converted %.loc10_50, constants.%.loc7_25.2
 // CHECK:STDOUT:   %.loc10_51: type = struct_type {.a: (i32, i32, i32), .b: (i32, i32, i32)}
 // CHECK:STDOUT:   %v.var: ref {.a: (i32, i32, i32), .b: (i32, i32, i32)} = var v
 // CHECK:STDOUT:   %v: ref {.a: (i32, i32, i32), .b: (i32, i32, i32)} = bind_name v, %v.var
@@ -39,7 +41,8 @@ fn G() {
 // CHECK:STDOUT:   %.loc10_74.2: ref (i32, i32, i32) = struct_access %v.var, member1
 // CHECK:STDOUT:   %.loc10_72: init (i32, i32, i32) = call %F.ref.loc10_71() to %.loc10_74.2
 // CHECK:STDOUT:   %.loc10_74.3: {.a: (i32, i32, i32), .b: (i32, i32, i32)} = struct_literal (%.loc10_62, %.loc10_72)
-// CHECK:STDOUT:   %.loc10_74.4: init {.a: (i32, i32, i32), .b: (i32, i32, i32)} = struct_init %.loc10_74.3, (%.loc10_62, %.loc10_72)
-// CHECK:STDOUT:   assign %v.var, %.loc10_74.4
+// CHECK:STDOUT:   %.loc10_74.4: init {.a: (i32, i32, i32), .b: (i32, i32, i32)} = struct_init (%.loc10_62, %.loc10_72) to %v.var
+// CHECK:STDOUT:   %.loc10_74.5: init {.a: (i32, i32, i32), .b: (i32, i32, i32)} = converted %.loc10_74.3, %.loc10_74.4
+// CHECK:STDOUT:   assign %v.var, %.loc10_74.5
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }

+ 6 - 4
toolchain/check/testdata/struct/one_entry.carbon

@@ -13,14 +13,16 @@ var y: {.a: i32} = x;
 // CHECK:STDOUT:   %x: ref {.a: i32} = bind_name x, %x.var
 // CHECK:STDOUT:   %.loc7_26: i32 = int_literal 4
 // CHECK:STDOUT:   %.loc7_27.1: {.a: i32} = struct_literal (%.loc7_26)
-// CHECK:STDOUT:   %.loc7_27.2: init {.a: i32} = struct_init %.loc7_27.1, (%.loc7_26)
-// CHECK:STDOUT:   assign %x.var, %.loc7_27.2
+// CHECK:STDOUT:   %.loc7_27.2: init {.a: i32} = struct_init (%.loc7_26) to %x.var
+// CHECK:STDOUT:   %.loc7_27.3: init {.a: i32} = converted %.loc7_27.1, %.loc7_27.2
+// CHECK:STDOUT:   assign %x.var, %.loc7_27.3
 // CHECK:STDOUT:   %.loc8_16: type = struct_type {.a: i32}
 // CHECK:STDOUT:   %y.var: ref {.a: i32} = var y
 // CHECK:STDOUT:   %y: ref {.a: i32} = bind_name y, %y.var
 // CHECK:STDOUT:   %x.ref: ref {.a: i32} = name_reference x, %x
 // CHECK:STDOUT:   %.loc8_20.1: ref i32 = struct_access %x.ref, member0
 // CHECK:STDOUT:   %.loc8_20.2: i32 = bind_value %.loc8_20.1
-// CHECK:STDOUT:   %.loc8_20.3: init {.a: i32} = struct_init %x.ref, (%.loc8_20.2)
-// CHECK:STDOUT:   assign %y.var, %.loc8_20.3
+// CHECK:STDOUT:   %.loc8_20.3: init {.a: i32} = struct_init (%.loc8_20.2) to %y.var
+// CHECK:STDOUT:   %.loc8_20.4: init {.a: i32} = converted %x.ref, %.loc8_20.3
+// CHECK:STDOUT:   assign %y.var, %.loc8_20.4
 // CHECK:STDOUT: }

+ 12 - 7
toolchain/check/testdata/struct/reorder_fields.carbon

@@ -38,15 +38,19 @@ fn F() -> {.a: i32, .b: f64} {
 // CHECK:STDOUT:   %.loc11_60: init i32 = call %MakeI32.ref()
 // CHECK:STDOUT:   %.loc11_62.1: {.b: f64, .a: i32} = struct_literal (%.loc11_44, %.loc11_60)
 // CHECK:STDOUT:   %.loc11_62.2: i32 = value_of_initializer %.loc11_60
-// CHECK:STDOUT:   %.loc11_62.3: f64 = value_of_initializer %.loc11_44
-// CHECK:STDOUT:   %.loc11_62.4: {.a: i32, .b: f64} = struct_value %.loc11_62.1, (%.loc11_62.2, %.loc11_62.3)
-// CHECK:STDOUT:   %x: {.a: i32, .b: f64} = bind_name x, %.loc11_62.4
+// CHECK:STDOUT:   %.loc11_62.3: i32 = converted %.loc11_60, %.loc11_62.2
+// CHECK:STDOUT:   %.loc11_62.4: f64 = value_of_initializer %.loc11_44
+// CHECK:STDOUT:   %.loc11_62.5: f64 = converted %.loc11_44, %.loc11_62.4
+// CHECK:STDOUT:   %.loc11_62.6: {.a: i32, .b: f64} = struct_value (%.loc11_62.3, %.loc11_62.5)
+// CHECK:STDOUT:   %.loc11_62.7: {.a: i32, .b: f64} = converted %.loc11_62.1, %.loc11_62.6
+// CHECK:STDOUT:   %x: {.a: i32, .b: f64} = bind_name x, %.loc11_62.7
 // CHECK:STDOUT:   %.loc12_27: type = struct_type {.b: f64, .a: i32}
 // CHECK:STDOUT:   %x.ref: {.a: i32, .b: f64} = name_reference x, %x
 // CHECK:STDOUT:   %.loc12_31.1: f64 = struct_access %x.ref, member1
 // CHECK:STDOUT:   %.loc12_31.2: i32 = struct_access %x.ref, member0
-// CHECK:STDOUT:   %.loc12_31.3: {.b: f64, .a: i32} = struct_value %x.ref, (%.loc12_31.1, %.loc12_31.2)
-// CHECK:STDOUT:   %y: {.b: f64, .a: i32} = bind_name y, %.loc12_31.3
+// CHECK:STDOUT:   %.loc12_31.3: {.b: f64, .a: i32} = struct_value (%.loc12_31.1, %.loc12_31.2)
+// CHECK:STDOUT:   %.loc12_31.4: {.b: f64, .a: i32} = converted %x.ref, %.loc12_31.3
+// CHECK:STDOUT:   %y: {.b: f64, .a: i32} = bind_name y, %.loc12_31.4
 // CHECK:STDOUT:   %y.ref: {.b: f64, .a: i32} = name_reference y, %y
 // CHECK:STDOUT:   %.loc13_10.1: i32 = struct_access %y.ref, member1
 // CHECK:STDOUT:   %.loc13_10.2: ref i32 = struct_access %return, member1
@@ -54,6 +58,7 @@ fn F() -> {.a: i32, .b: f64} {
 // CHECK:STDOUT:   %.loc13_10.4: f64 = struct_access %y.ref, member0
 // CHECK:STDOUT:   %.loc13_10.5: ref f64 = struct_access %return, member0
 // CHECK:STDOUT:   %.loc13_10.6: init f64 = initialize_from %.loc13_10.4 to %.loc13_10.5
-// CHECK:STDOUT:   %.loc13_10.7: init {.a: i32, .b: f64} = struct_init %y.ref, (%.loc13_10.3, %.loc13_10.6)
-// CHECK:STDOUT:   return %.loc13_10.7
+// CHECK:STDOUT:   %.loc13_10.7: init {.a: i32, .b: f64} = struct_init (%.loc13_10.3, %.loc13_10.6) to %return
+// CHECK:STDOUT:   %.loc13_10.8: init {.a: i32, .b: f64} = converted %y.ref, %.loc13_10.7
+// CHECK:STDOUT:   return %.loc13_10.8
 // CHECK:STDOUT: }

+ 16 - 10
toolchain/check/testdata/struct/tuple_as_element.carbon

@@ -14,7 +14,8 @@ var y: {.a: i32, .b: (i32,)} = x;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file "tuple_as_element.carbon" {
-// CHECK:STDOUT:   %.loc7_27: (type,) = tuple_literal (i32)
+// CHECK:STDOUT:   %.loc7_27.1: (type,) = tuple_literal (i32)
+// CHECK:STDOUT:   %.loc7_27.2: type = converted %.loc7_27.1, constants.%.loc7_27.2
 // CHECK:STDOUT:   %.loc7_28: type = struct_type {.a: i32, .b: (i32,)}
 // CHECK:STDOUT:   %x.var: ref {.a: i32, .b: (i32,)} = var x
 // CHECK:STDOUT:   %x: ref {.a: i32, .b: (i32,)} = bind_name x, %x.var
@@ -24,12 +25,15 @@ var y: {.a: i32, .b: (i32,)} = x;
 // CHECK:STDOUT:   %.loc7_50.1: {.a: i32, .b: (i32,)} = struct_literal (%.loc7_38, %.loc7_49.1)
 // CHECK:STDOUT:   %.loc7_50.2: ref i32 = struct_access %x.var, member0
 // CHECK:STDOUT:   %.loc7_50.3: init i32 = initialize_from %.loc7_38 to %.loc7_50.2
-// CHECK:STDOUT:   %.loc7_49.2: init (i32,) = tuple_init %.loc7_49.1, (%.loc7_47)
 // CHECK:STDOUT:   %.loc7_50.4: ref (i32,) = struct_access %x.var, member1
-// CHECK:STDOUT:   %.loc7_50.5: init (i32,) = initialize_from %.loc7_49.2 to %.loc7_50.4
-// CHECK:STDOUT:   %.loc7_50.6: init {.a: i32, .b: (i32,)} = struct_init %.loc7_50.1, (%.loc7_50.3, %.loc7_50.5)
-// CHECK:STDOUT:   assign %x.var, %.loc7_50.6
+// CHECK:STDOUT:   %.loc7_49.2: init (i32,) = tuple_init (%.loc7_47) to %.loc7_50.4
+// CHECK:STDOUT:   %.loc7_49.3: init (i32,) = converted %.loc7_49.1, %.loc7_49.2
+// CHECK:STDOUT:   %.loc7_50.5: init (i32,) = initialize_from %.loc7_49.3 to %.loc7_50.4
+// CHECK:STDOUT:   %.loc7_50.6: init {.a: i32, .b: (i32,)} = struct_init (%.loc7_50.3, %.loc7_50.5) to %x.var
+// CHECK:STDOUT:   %.loc7_50.7: init {.a: i32, .b: (i32,)} = converted %.loc7_50.1, %.loc7_50.6
+// CHECK:STDOUT:   assign %x.var, %.loc7_50.7
 // CHECK:STDOUT:   %.loc8_27: (type,) = tuple_literal (i32)
+// CHECK:STDOUT:   %.loc7_27.3: type = converted %.loc8_27, constants.%.loc7_27.2
 // CHECK:STDOUT:   %.loc8_28: type = struct_type {.a: i32, .b: (i32,)}
 // CHECK:STDOUT:   %y.var: ref {.a: i32, .b: (i32,)} = var y
 // CHECK:STDOUT:   %y: ref {.a: i32, .b: (i32,)} = bind_name y, %y.var
@@ -41,9 +45,11 @@ var y: {.a: i32, .b: (i32,)} = x;
 // CHECK:STDOUT:   %.loc8_32.5: ref (i32,) = struct_access %x.ref, member1
 // CHECK:STDOUT:   %.loc8_32.6: ref i32 = tuple_access %.loc8_32.5, member0
 // CHECK:STDOUT:   %.loc8_32.7: i32 = bind_value %.loc8_32.6
-// CHECK:STDOUT:   %.loc8_32.8: init (i32,) = tuple_init %.loc8_32.5, (%.loc8_32.7)
-// CHECK:STDOUT:   %.loc8_32.9: ref (i32,) = struct_access %y.var, member1
-// CHECK:STDOUT:   %.loc8_32.10: init (i32,) = initialize_from %.loc8_32.8 to %.loc8_32.9
-// CHECK:STDOUT:   %.loc8_32.11: init {.a: i32, .b: (i32,)} = struct_init %x.ref, (%.loc8_32.4, %.loc8_32.10)
-// CHECK:STDOUT:   assign %y.var, %.loc8_32.11
+// CHECK:STDOUT:   %.loc8_32.8: ref (i32,) = struct_access %y.var, member1
+// CHECK:STDOUT:   %.loc8_32.9: init (i32,) = tuple_init (%.loc8_32.7) to %.loc8_32.8
+// CHECK:STDOUT:   %.loc8_32.10: init (i32,) = converted %.loc8_32.5, %.loc8_32.9
+// CHECK:STDOUT:   %.loc8_32.11: init (i32,) = initialize_from %.loc8_32.10 to %.loc8_32.8
+// CHECK:STDOUT:   %.loc8_32.12: init {.a: i32, .b: (i32,)} = struct_init (%.loc8_32.4, %.loc8_32.11) to %y.var
+// CHECK:STDOUT:   %.loc8_32.13: init {.a: i32, .b: (i32,)} = converted %x.ref, %.loc8_32.12
+// CHECK:STDOUT:   assign %y.var, %.loc8_32.13
 // CHECK:STDOUT: }

+ 6 - 4
toolchain/check/testdata/struct/two_entries.carbon

@@ -22,8 +22,9 @@ var y: {.a: i32, .b: i32} = x;
 // CHECK:STDOUT:   %.loc7_44.3: init i32 = initialize_from %.loc7_35 to %.loc7_44.2
 // CHECK:STDOUT:   %.loc7_44.4: ref i32 = struct_access %x.var, member1
 // CHECK:STDOUT:   %.loc7_44.5: init i32 = initialize_from %.loc7_43 to %.loc7_44.4
-// CHECK:STDOUT:   %.loc7_44.6: init {.a: i32, .b: i32} = struct_init %.loc7_44.1, (%.loc7_44.3, %.loc7_44.5)
-// CHECK:STDOUT:   assign %x.var, %.loc7_44.6
+// CHECK:STDOUT:   %.loc7_44.6: init {.a: i32, .b: i32} = struct_init (%.loc7_44.3, %.loc7_44.5) to %x.var
+// CHECK:STDOUT:   %.loc7_44.7: init {.a: i32, .b: i32} = converted %.loc7_44.1, %.loc7_44.6
+// CHECK:STDOUT:   assign %x.var, %.loc7_44.7
 // CHECK:STDOUT:   %.loc8_25: type = struct_type {.a: i32, .b: i32}
 // CHECK:STDOUT:   %y.var: ref {.a: i32, .b: i32} = var y
 // CHECK:STDOUT:   %y: ref {.a: i32, .b: i32} = bind_name y, %y.var
@@ -36,6 +37,7 @@ var y: {.a: i32, .b: i32} = x;
 // CHECK:STDOUT:   %.loc8_29.6: i32 = bind_value %.loc8_29.5
 // CHECK:STDOUT:   %.loc8_29.7: ref i32 = struct_access %y.var, member1
 // CHECK:STDOUT:   %.loc8_29.8: init i32 = initialize_from %.loc8_29.6 to %.loc8_29.7
-// CHECK:STDOUT:   %.loc8_29.9: init {.a: i32, .b: i32} = struct_init %x.ref, (%.loc8_29.4, %.loc8_29.8)
-// CHECK:STDOUT:   assign %y.var, %.loc8_29.9
+// CHECK:STDOUT:   %.loc8_29.9: init {.a: i32, .b: i32} = struct_init (%.loc8_29.4, %.loc8_29.8) to %y.var
+// CHECK:STDOUT:   %.loc8_29.10: init {.a: i32, .b: i32} = converted %x.ref, %.loc8_29.9
+// CHECK:STDOUT:   assign %y.var, %.loc8_29.10
 // CHECK:STDOUT: }

+ 9 - 5
toolchain/check/testdata/tuples/empty.carbon

@@ -12,16 +12,20 @@ var y: () = x;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file "empty.carbon" {
-// CHECK:STDOUT:   %.loc7_9: () = tuple_literal ()
+// CHECK:STDOUT:   %.loc7_9.1: () = tuple_literal ()
+// CHECK:STDOUT:   %.loc7_9.2: type = converted %.loc7_9.1, constants.%.loc7
 // CHECK:STDOUT:   %x.var: ref () = var x
 // CHECK:STDOUT:   %x: ref () = bind_name x, %x.var
 // CHECK:STDOUT:   %.loc7_14.1: () = tuple_literal ()
-// CHECK:STDOUT:   %.loc7_14.2: init () = tuple_init %.loc7_14.1, ()
-// CHECK:STDOUT:   assign %x.var, %.loc7_14.2
+// CHECK:STDOUT:   %.loc7_14.2: init () = tuple_init () to %x.var
+// CHECK:STDOUT:   %.loc7_14.3: init () = converted %.loc7_14.1, %.loc7_14.2
+// CHECK:STDOUT:   assign %x.var, %.loc7_14.3
 // CHECK:STDOUT:   %.loc8_9: () = tuple_literal ()
+// CHECK:STDOUT:   %.loc7_9.3: type = converted %.loc8_9, constants.%.loc7
 // CHECK:STDOUT:   %y.var: ref () = var y
 // CHECK:STDOUT:   %y: ref () = bind_name y, %y.var
 // CHECK:STDOUT:   %x.ref: ref () = name_reference x, %x
-// CHECK:STDOUT:   %.loc8_13: init () = tuple_init %x.ref, ()
-// CHECK:STDOUT:   assign %y.var, %.loc8_13
+// CHECK:STDOUT:   %.loc8_13.1: init () = tuple_init () to %y.var
+// CHECK:STDOUT:   %.loc8_13.2: init () = converted %x.ref, %.loc8_13.1
+// CHECK:STDOUT:   assign %y.var, %.loc8_13.2
 // CHECK:STDOUT: }

+ 2 - 1
toolchain/check/testdata/tuples/fail_assign_empty.carbon

@@ -16,7 +16,8 @@ var x: (i32,) = ();
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file "fail_assign_empty.carbon" {
-// CHECK:STDOUT:   %.loc10_13: (type,) = tuple_literal (i32)
+// CHECK:STDOUT:   %.loc10_13.1: (type,) = tuple_literal (i32)
+// CHECK:STDOUT:   %.loc10_13.2: type = converted %.loc10_13.1, constants.%.loc10_13.2
 // CHECK:STDOUT:   %x.var: ref (i32,) = var x
 // CHECK:STDOUT:   %x: ref (i32,) = bind_name x, %x.var
 // CHECK:STDOUT:   %.loc10_18: () = tuple_literal ()

+ 4 - 1
toolchain/check/testdata/tuples/fail_assign_nested.carbon

@@ -24,7 +24,10 @@ var x: ((i32, i32), (i32, i32)) = ((1, 2, 3), (4, 5, 6));
 // CHECK:STDOUT: file "fail_assign_nested.carbon" {
 // CHECK:STDOUT:   %.loc10_18: (type, type) = tuple_literal (i32, i32)
 // CHECK:STDOUT:   %.loc10_30: (type, type) = tuple_literal (i32, i32)
-// CHECK:STDOUT:   %.loc10_31: ((type, type), (type, type)) = tuple_literal (%.loc10_18, %.loc10_30)
+// CHECK:STDOUT:   %.loc10_31.1: ((type, type), (type, type)) = tuple_literal (%.loc10_18, %.loc10_30)
+// CHECK:STDOUT:   %.loc10_31.2: type = converted %.loc10_18, constants.%.loc10_31.2
+// CHECK:STDOUT:   %.loc10_31.3: type = converted %.loc10_30, constants.%.loc10_31.2
+// CHECK:STDOUT:   %.loc10_31.4: type = converted %.loc10_31.1, constants.%.loc10_31.3
 // CHECK:STDOUT:   %x.var: ref ((i32, i32), (i32, i32)) = var x
 // CHECK:STDOUT:   %x: ref ((i32, i32), (i32, i32)) = bind_name x, %x.var
 // CHECK:STDOUT:   %.loc10_37: i32 = int_literal 1

+ 2 - 1
toolchain/check/testdata/tuples/fail_assign_to_empty.carbon

@@ -14,7 +14,8 @@ var x: () = (66);
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file "fail_assign_to_empty.carbon" {
-// CHECK:STDOUT:   %.loc10_9: () = tuple_literal ()
+// CHECK:STDOUT:   %.loc10_9.1: () = tuple_literal ()
+// CHECK:STDOUT:   %.loc10_9.2: type = converted %.loc10_9.1, constants.%.loc10
 // CHECK:STDOUT:   %x.var: ref () = var x
 // CHECK:STDOUT:   %x: ref () = bind_name x, %x.var
 // CHECK:STDOUT:   %.loc10_14: i32 = int_literal 66

+ 2 - 1
toolchain/check/testdata/tuples/fail_element_type_mismatch.carbon

@@ -17,7 +17,8 @@ var x: (i32, i32) = (2, 65.89);
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file "fail_element_type_mismatch.carbon" {
-// CHECK:STDOUT:   %.loc10_17: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc10_17.1: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc10_17.2: type = converted %.loc10_17.1, constants.%.loc10_17.2
 // CHECK:STDOUT:   %x.var: ref (i32, i32) = var x
 // CHECK:STDOUT:   %x: ref (i32, i32) = bind_name x, %x.var
 // CHECK:STDOUT:   %.loc10_22: i32 = int_literal 2

+ 2 - 1
toolchain/check/testdata/tuples/fail_nested_incomplete.carbon

@@ -29,7 +29,8 @@ var p: Incomplete* = &t[1];
 // CHECK:STDOUT:   class_declaration @Incomplete, ()
 // CHECK:STDOUT:   %Incomplete: type = class_type @Incomplete
 // CHECK:STDOUT:   %Incomplete.ref.loc15: type = name_reference Incomplete, %Incomplete
-// CHECK:STDOUT:   %.loc15: (type, type) = tuple_literal (i32, %Incomplete.ref.loc15)
+// CHECK:STDOUT:   %.loc15_24.1: (type, type) = tuple_literal (i32, %Incomplete.ref.loc15)
+// CHECK:STDOUT:   %.loc15_24.2: type = converted %.loc15_24.1, constants.%.loc15_24.2
 // CHECK:STDOUT:   %t.var: ref <error> = var t
 // CHECK:STDOUT:   %t: ref <error> = bind_name t, %t.var
 // CHECK:STDOUT:   %Incomplete.ref.loc20: type = name_reference Incomplete, %Incomplete

+ 2 - 1
toolchain/check/testdata/tuples/fail_too_few_element.carbon

@@ -17,7 +17,8 @@ var x: (i32, i32) = (2, );
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file "fail_too_few_element.carbon" {
-// CHECK:STDOUT:   %.loc10_17: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc10_17.1: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc10_17.2: type = converted %.loc10_17.1, constants.%.loc10_17.2
 // CHECK:STDOUT:   %x.var: ref (i32, i32) = var x
 // CHECK:STDOUT:   %x: ref (i32, i32) = bind_name x, %x.var
 // CHECK:STDOUT:   %.loc10_22: i32 = int_literal 2

+ 2 - 1
toolchain/check/testdata/tuples/fail_type_assign.carbon

@@ -15,7 +15,8 @@ var x: (i32, ) = (i32, );
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file "fail_type_assign.carbon" {
-// CHECK:STDOUT:   %.loc10_14: (type,) = tuple_literal (i32)
+// CHECK:STDOUT:   %.loc10_14.1: (type,) = tuple_literal (i32)
+// CHECK:STDOUT:   %.loc10_14.2: type = converted %.loc10_14.1, constants.%.loc10_14.2
 // CHECK:STDOUT:   %x.var: ref (i32,) = var x
 // CHECK:STDOUT:   %x: ref (i32,) = bind_name x, %x.var
 // CHECK:STDOUT:   %.loc10_24: (type,) = tuple_literal (i32)

+ 2 - 1
toolchain/check/testdata/tuples/fail_value_as_type.carbon

@@ -16,7 +16,8 @@ var x: (1, );
 // CHECK:STDOUT:
 // CHECK:STDOUT: file "fail_value_as_type.carbon" {
 // CHECK:STDOUT:   %.loc10_9: i32 = int_literal 1
-// CHECK:STDOUT:   %.loc10_12: (i32,) = tuple_literal (%.loc10_9)
+// CHECK:STDOUT:   %.loc10_12.1: (i32,) = tuple_literal (%.loc10_9)
+// CHECK:STDOUT:   %.loc10_12.2: type = converted %.loc10_12.1, constants.%.loc10_12.2
 // CHECK:STDOUT:   %x.var: ref (<error>,) = var x
 // CHECK:STDOUT:   %x: ref (<error>,) = bind_name x, %x.var
 // CHECK:STDOUT: }

+ 8 - 4
toolchain/check/testdata/tuples/nested_tuple.carbon

@@ -18,7 +18,9 @@ var x: ((i32, i32), i32) = ((12, 76), 6);
 // CHECK:STDOUT:
 // CHECK:STDOUT: file "nested_tuple.carbon" {
 // CHECK:STDOUT:   %.loc7_18: (type, type) = tuple_literal (i32, i32)
-// CHECK:STDOUT:   %.loc7_24: ((type, type), type) = tuple_literal (%.loc7_18, i32)
+// CHECK:STDOUT:   %.loc7_24.1: ((type, type), type) = tuple_literal (%.loc7_18, i32)
+// CHECK:STDOUT:   %.loc7_24.2: type = converted %.loc7_18, constants.%.loc7_24.2
+// CHECK:STDOUT:   %.loc7_24.3: type = converted %.loc7_24.1, constants.%.loc7_24.3
 // CHECK:STDOUT:   %x.var: ref ((i32, i32), i32) = var x
 // CHECK:STDOUT:   %x: ref ((i32, i32), i32) = bind_name x, %x.var
 // CHECK:STDOUT:   %.loc7_30: i32 = int_literal 12
@@ -31,9 +33,11 @@ var x: ((i32, i32), i32) = ((12, 76), 6);
 // CHECK:STDOUT:   %.loc7_36.3: init i32 = initialize_from %.loc7_30 to %.loc7_36.2
 // CHECK:STDOUT:   %.loc7_36.4: ref i32 = tuple_access %.loc7_40.2, member1
 // CHECK:STDOUT:   %.loc7_36.5: init i32 = initialize_from %.loc7_34 to %.loc7_36.4
-// CHECK:STDOUT:   %.loc7_36.6: init (i32, i32) = tuple_init %.loc7_36.1, (%.loc7_36.3, %.loc7_36.5)
+// CHECK:STDOUT:   %.loc7_36.6: init (i32, i32) = tuple_init (%.loc7_36.3, %.loc7_36.5) to %.loc7_40.2
+// CHECK:STDOUT:   %.loc7_36.7: init (i32, i32) = converted %.loc7_36.1, %.loc7_36.6
 // CHECK:STDOUT:   %.loc7_40.3: ref i32 = tuple_access %x.var, member1
 // CHECK:STDOUT:   %.loc7_40.4: init i32 = initialize_from %.loc7_39 to %.loc7_40.3
-// CHECK:STDOUT:   %.loc7_40.5: init ((i32, i32), i32) = tuple_init %.loc7_40.1, (%.loc7_36.6, %.loc7_40.4)
-// CHECK:STDOUT:   assign %x.var, %.loc7_40.5
+// CHECK:STDOUT:   %.loc7_40.5: init ((i32, i32), i32) = tuple_init (%.loc7_36.7, %.loc7_40.4) to %x.var
+// CHECK:STDOUT:   %.loc7_40.6: init ((i32, i32), i32) = converted %.loc7_40.1, %.loc7_40.5
+// CHECK:STDOUT:   assign %x.var, %.loc7_40.6
 // CHECK:STDOUT: }

+ 13 - 6
toolchain/check/testdata/tuples/nested_tuple_in_place.carbon

@@ -40,7 +40,10 @@ fn H() {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %.loc10_25: (type, type, type) = tuple_literal (i32, i32, i32)
 // CHECK:STDOUT:   %.loc10_42: (type, type, type) = tuple_literal (i32, i32, i32)
-// CHECK:STDOUT:   %.loc10_43: ((type, type, type), (type, type, type)) = tuple_literal (%.loc10_25, %.loc10_42)
+// CHECK:STDOUT:   %.loc10_43.1: ((type, type, type), (type, type, type)) = tuple_literal (%.loc10_25, %.loc10_42)
+// CHECK:STDOUT:   %.loc7_25.1: type = converted %.loc10_25, constants.%.loc7_25.2
+// CHECK:STDOUT:   %.loc7_25.2: type = converted %.loc10_42, constants.%.loc7_25.2
+// CHECK:STDOUT:   %.loc10_43.2: type = converted %.loc10_43.1, constants.%.loc10_43.2
 // CHECK:STDOUT:   %v.var: ref ((i32, i32, i32), (i32, i32, i32)) = var v
 // CHECK:STDOUT:   %v: ref ((i32, i32, i32), (i32, i32, i32)) = bind_name v, %v.var
 // CHECK:STDOUT:   %F.ref.loc10_48: <function> = name_reference F, file.%F
@@ -50,15 +53,18 @@ fn H() {
 // CHECK:STDOUT:   %.loc10_56.2: ref (i32, i32, i32) = tuple_access %v.var, member1
 // CHECK:STDOUT:   %.loc10_54: init (i32, i32, i32) = call %F.ref.loc10_53() to %.loc10_56.2
 // CHECK:STDOUT:   %.loc10_56.3: ((i32, i32, i32), (i32, i32, i32)) = tuple_literal (%.loc10_49, %.loc10_54)
-// CHECK:STDOUT:   %.loc10_56.4: init ((i32, i32, i32), (i32, i32, i32)) = tuple_init %.loc10_56.3, (%.loc10_49, %.loc10_54)
-// CHECK:STDOUT:   assign %v.var, %.loc10_56.4
+// CHECK:STDOUT:   %.loc10_56.4: init ((i32, i32, i32), (i32, i32, i32)) = tuple_init (%.loc10_49, %.loc10_54) to %v.var
+// CHECK:STDOUT:   %.loc10_56.5: init ((i32, i32, i32), (i32, i32, i32)) = converted %.loc10_56.3, %.loc10_56.4
+// CHECK:STDOUT:   assign %v.var, %.loc10_56.5
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @H() {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %.loc14_30: (type, type, type) = tuple_literal (i32, i32, i32)
-// CHECK:STDOUT:   %.loc14_36: (type, (type, type, type), type) = tuple_literal (i32, %.loc14_30, i32)
+// CHECK:STDOUT:   %.loc14_36.1: (type, (type, type, type), type) = tuple_literal (i32, %.loc14_30, i32)
+// CHECK:STDOUT:   %.loc7: type = converted %.loc14_30, constants.%.loc7_25.2
+// CHECK:STDOUT:   %.loc14_36.2: type = converted %.loc14_36.1, constants.%.loc14_36.2
 // CHECK:STDOUT:   %v.var: ref (i32, (i32, i32, i32), i32) = var v
 // CHECK:STDOUT:   %v: ref (i32, (i32, i32, i32), i32) = bind_name v, %v.var
 // CHECK:STDOUT:   %.loc14_41: i32 = int_literal 1
@@ -71,7 +77,8 @@ fn H() {
 // CHECK:STDOUT:   %.loc14_50.4: init i32 = initialize_from %.loc14_41 to %.loc14_50.3
 // CHECK:STDOUT:   %.loc14_50.5: ref i32 = tuple_access %v.var, member2
 // CHECK:STDOUT:   %.loc14_50.6: init i32 = initialize_from %.loc14_49 to %.loc14_50.5
-// CHECK:STDOUT:   %.loc14_50.7: init (i32, (i32, i32, i32), i32) = tuple_init %.loc14_50.2, (%.loc14_50.4, %.loc14_45, %.loc14_50.6)
-// CHECK:STDOUT:   assign %v.var, %.loc14_50.7
+// CHECK:STDOUT:   %.loc14_50.7: init (i32, (i32, i32, i32), i32) = tuple_init (%.loc14_50.4, %.loc14_45, %.loc14_50.6) to %v.var
+// CHECK:STDOUT:   %.loc14_50.8: init (i32, (i32, i32, i32), i32) = converted %.loc14_50.2, %.loc14_50.7
+// CHECK:STDOUT:   assign %v.var, %.loc14_50.8
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }

+ 9 - 5
toolchain/check/testdata/tuples/one_element.carbon

@@ -13,19 +13,23 @@ var y: (i32,) = x;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file "one_element.carbon" {
-// CHECK:STDOUT:   %.loc7_13: (type,) = tuple_literal (i32)
+// CHECK:STDOUT:   %.loc7_13.1: (type,) = tuple_literal (i32)
+// CHECK:STDOUT:   %.loc7_13.2: type = converted %.loc7_13.1, constants.%.loc7_13.2
 // CHECK:STDOUT:   %x.var: ref (i32,) = var x
 // CHECK:STDOUT:   %x: ref (i32,) = bind_name x, %x.var
 // CHECK:STDOUT:   %.loc7_18: i32 = int_literal 4
 // CHECK:STDOUT:   %.loc7_20.1: (i32,) = tuple_literal (%.loc7_18)
-// CHECK:STDOUT:   %.loc7_20.2: init (i32,) = tuple_init %.loc7_20.1, (%.loc7_18)
-// CHECK:STDOUT:   assign %x.var, %.loc7_20.2
+// CHECK:STDOUT:   %.loc7_20.2: init (i32,) = tuple_init (%.loc7_18) to %x.var
+// CHECK:STDOUT:   %.loc7_20.3: init (i32,) = converted %.loc7_20.1, %.loc7_20.2
+// CHECK:STDOUT:   assign %x.var, %.loc7_20.3
 // CHECK:STDOUT:   %.loc8_13: (type,) = tuple_literal (i32)
+// CHECK:STDOUT:   %.loc7_13.3: type = converted %.loc8_13, constants.%.loc7_13.2
 // CHECK:STDOUT:   %y.var: ref (i32,) = var y
 // CHECK:STDOUT:   %y: ref (i32,) = bind_name y, %y.var
 // CHECK:STDOUT:   %x.ref: ref (i32,) = name_reference x, %x
 // CHECK:STDOUT:   %.loc8_17.1: ref i32 = tuple_access %x.ref, member0
 // CHECK:STDOUT:   %.loc8_17.2: i32 = bind_value %.loc8_17.1
-// CHECK:STDOUT:   %.loc8_17.3: init (i32,) = tuple_init %x.ref, (%.loc8_17.2)
-// CHECK:STDOUT:   assign %y.var, %.loc8_17.3
+// CHECK:STDOUT:   %.loc8_17.3: init (i32,) = tuple_init (%.loc8_17.2) to %y.var
+// CHECK:STDOUT:   %.loc8_17.4: init (i32,) = converted %x.ref, %.loc8_17.3
+// CHECK:STDOUT:   assign %y.var, %.loc8_17.4
 // CHECK:STDOUT: }

+ 9 - 5
toolchain/check/testdata/tuples/two_elements.carbon

@@ -14,7 +14,8 @@ var y: (i32, i32) = x;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file "two_elements.carbon" {
-// CHECK:STDOUT:   %.loc7_17: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc7_17.1: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc7_17.2: type = converted %.loc7_17.1, constants.%.loc7_17.2
 // CHECK:STDOUT:   %x.var: ref (i32, i32) = var x
 // CHECK:STDOUT:   %x: ref (i32, i32) = bind_name x, %x.var
 // CHECK:STDOUT:   %.loc7_22: i32 = int_literal 4
@@ -24,9 +25,11 @@ var y: (i32, i32) = x;
 // CHECK:STDOUT:   %.loc7_28.3: init i32 = initialize_from %.loc7_22 to %.loc7_28.2
 // CHECK:STDOUT:   %.loc7_28.4: ref i32 = tuple_access %x.var, member1
 // CHECK:STDOUT:   %.loc7_28.5: init i32 = initialize_from %.loc7_25 to %.loc7_28.4
-// CHECK:STDOUT:   %.loc7_28.6: init (i32, i32) = tuple_init %.loc7_28.1, (%.loc7_28.3, %.loc7_28.5)
-// CHECK:STDOUT:   assign %x.var, %.loc7_28.6
+// CHECK:STDOUT:   %.loc7_28.6: init (i32, i32) = tuple_init (%.loc7_28.3, %.loc7_28.5) to %x.var
+// CHECK:STDOUT:   %.loc7_28.7: init (i32, i32) = converted %.loc7_28.1, %.loc7_28.6
+// CHECK:STDOUT:   assign %x.var, %.loc7_28.7
 // CHECK:STDOUT:   %.loc8_17: (type, type) = tuple_literal (i32, i32)
+// CHECK:STDOUT:   %.loc7_17.3: type = converted %.loc8_17, constants.%.loc7_17.2
 // CHECK:STDOUT:   %y.var: ref (i32, i32) = var y
 // CHECK:STDOUT:   %y: ref (i32, i32) = bind_name y, %y.var
 // CHECK:STDOUT:   %x.ref: ref (i32, i32) = name_reference x, %x
@@ -38,6 +41,7 @@ var y: (i32, i32) = x;
 // CHECK:STDOUT:   %.loc8_21.6: i32 = bind_value %.loc8_21.5
 // CHECK:STDOUT:   %.loc8_21.7: ref i32 = tuple_access %y.var, member1
 // CHECK:STDOUT:   %.loc8_21.8: init i32 = initialize_from %.loc8_21.6 to %.loc8_21.7
-// CHECK:STDOUT:   %.loc8_21.9: init (i32, i32) = tuple_init %x.ref, (%.loc8_21.4, %.loc8_21.8)
-// CHECK:STDOUT:   assign %y.var, %.loc8_21.9
+// CHECK:STDOUT:   %.loc8_21.9: init (i32, i32) = tuple_init (%.loc8_21.4, %.loc8_21.8) to %y.var
+// CHECK:STDOUT:   %.loc8_21.10: init (i32, i32) = converted %x.ref, %.loc8_21.9
+// CHECK:STDOUT:   assign %y.var, %.loc8_21.10
 // CHECK:STDOUT: }

+ 24 - 16
toolchain/check/testdata/while/break_continue.carbon

@@ -61,14 +61,16 @@ fn While() {
 // CHECK:STDOUT: !while.cond.loc17:
 // CHECK:STDOUT:   %A.ref: <function> = name_reference A, file.%A
 // CHECK:STDOUT:   %.loc17_11: init bool = call %A.ref()
-// CHECK:STDOUT:   %.loc17_13: bool = value_of_initializer %.loc17_11
-// CHECK:STDOUT:   if %.loc17_13 br !while.body.loc17 else br !while.done.loc17
+// CHECK:STDOUT:   %.loc17_13.1: bool = value_of_initializer %.loc17_11
+// CHECK:STDOUT:   %.loc17_13.2: bool = converted %.loc17_11, %.loc17_13.1
+// CHECK:STDOUT:   if %.loc17_13.2 br !while.body.loc17 else br !while.done.loc17
 // CHECK:STDOUT:
 // CHECK:STDOUT: !while.body.loc17:
 // CHECK:STDOUT:   %B.ref: <function> = name_reference B, file.%B
 // CHECK:STDOUT:   %.loc18_10: init bool = call %B.ref()
-// CHECK:STDOUT:   %.loc18_12: bool = value_of_initializer %.loc18_10
-// CHECK:STDOUT:   if %.loc18_12 br !if.then.loc18 else br !if.else.loc18
+// CHECK:STDOUT:   %.loc18_12.1: bool = value_of_initializer %.loc18_10
+// CHECK:STDOUT:   %.loc18_12.2: bool = converted %.loc18_10, %.loc18_12.1
+// CHECK:STDOUT:   if %.loc18_12.2 br !if.then.loc18 else br !if.else.loc18
 // CHECK:STDOUT:
 // CHECK:STDOUT: !if.then.loc18:
 // CHECK:STDOUT:   br !while.cond.loc17
@@ -76,8 +78,9 @@ fn While() {
 // CHECK:STDOUT: !if.else.loc18:
 // CHECK:STDOUT:   %C.ref: <function> = name_reference C, file.%C
 // CHECK:STDOUT:   %.loc19_10: init bool = call %C.ref()
-// CHECK:STDOUT:   %.loc19_12: bool = value_of_initializer %.loc19_10
-// CHECK:STDOUT:   if %.loc19_12 br !if.then.loc19 else br !if.else.loc19
+// CHECK:STDOUT:   %.loc19_12.1: bool = value_of_initializer %.loc19_10
+// CHECK:STDOUT:   %.loc19_12.2: bool = converted %.loc19_10, %.loc19_12.1
+// CHECK:STDOUT:   if %.loc19_12.2 br !if.then.loc19 else br !if.else.loc19
 // CHECK:STDOUT:
 // CHECK:STDOUT: !if.then.loc19:
 // CHECK:STDOUT:   br !while.done.loc17
@@ -88,14 +91,16 @@ fn While() {
 // CHECK:STDOUT: !while.cond.loc20:
 // CHECK:STDOUT:   %D.ref: <function> = name_reference D, file.%D
 // CHECK:STDOUT:   %.loc20_13: init bool = call %D.ref()
-// CHECK:STDOUT:   %.loc20_15: bool = value_of_initializer %.loc20_13
-// CHECK:STDOUT:   if %.loc20_15 br !while.body.loc20 else br !while.done.loc20
+// CHECK:STDOUT:   %.loc20_15.1: bool = value_of_initializer %.loc20_13
+// CHECK:STDOUT:   %.loc20_15.2: bool = converted %.loc20_13, %.loc20_15.1
+// CHECK:STDOUT:   if %.loc20_15.2 br !while.body.loc20 else br !while.done.loc20
 // CHECK:STDOUT:
 // CHECK:STDOUT: !while.body.loc20:
 // CHECK:STDOUT:   %E.ref: <function> = name_reference E, file.%E
 // CHECK:STDOUT:   %.loc21_12: init bool = call %E.ref()
-// CHECK:STDOUT:   %.loc21_14: bool = value_of_initializer %.loc21_12
-// CHECK:STDOUT:   if %.loc21_14 br !if.then.loc21 else br !if.else.loc21
+// CHECK:STDOUT:   %.loc21_14.1: bool = value_of_initializer %.loc21_12
+// CHECK:STDOUT:   %.loc21_14.2: bool = converted %.loc21_12, %.loc21_14.1
+// CHECK:STDOUT:   if %.loc21_14.2 br !if.then.loc21 else br !if.else.loc21
 // CHECK:STDOUT:
 // CHECK:STDOUT: !if.then.loc21:
 // CHECK:STDOUT:   br !while.cond.loc20
@@ -103,8 +108,9 @@ fn While() {
 // CHECK:STDOUT: !if.else.loc21:
 // CHECK:STDOUT:   %F.ref: <function> = name_reference F, file.%F
 // CHECK:STDOUT:   %.loc22_12: init bool = call %F.ref()
-// CHECK:STDOUT:   %.loc22_14: bool = value_of_initializer %.loc22_12
-// CHECK:STDOUT:   if %.loc22_14 br !if.then.loc22 else br !if.else.loc22
+// CHECK:STDOUT:   %.loc22_14.1: bool = value_of_initializer %.loc22_12
+// CHECK:STDOUT:   %.loc22_14.2: bool = converted %.loc22_12, %.loc22_14.1
+// CHECK:STDOUT:   if %.loc22_14.2 br !if.then.loc22 else br !if.else.loc22
 // CHECK:STDOUT:
 // CHECK:STDOUT: !if.then.loc22:
 // CHECK:STDOUT:   br !while.done.loc20
@@ -115,8 +121,9 @@ fn While() {
 // CHECK:STDOUT: !while.done.loc20:
 // CHECK:STDOUT:   %G.ref: <function> = name_reference G, file.%G
 // CHECK:STDOUT:   %.loc24_10: init bool = call %G.ref()
-// CHECK:STDOUT:   %.loc24_12: bool = value_of_initializer %.loc24_10
-// CHECK:STDOUT:   if %.loc24_12 br !if.then.loc24 else br !if.else.loc24
+// CHECK:STDOUT:   %.loc24_12.1: bool = value_of_initializer %.loc24_10
+// CHECK:STDOUT:   %.loc24_12.2: bool = converted %.loc24_10, %.loc24_12.1
+// CHECK:STDOUT:   if %.loc24_12.2 br !if.then.loc24 else br !if.else.loc24
 // CHECK:STDOUT:
 // CHECK:STDOUT: !if.then.loc24:
 // CHECK:STDOUT:   br !while.cond.loc17
@@ -124,8 +131,9 @@ fn While() {
 // CHECK:STDOUT: !if.else.loc24:
 // CHECK:STDOUT:   %H.ref: <function> = name_reference H, file.%H
 // CHECK:STDOUT:   %.loc25_10: init bool = call %H.ref()
-// CHECK:STDOUT:   %.loc25_12: bool = value_of_initializer %.loc25_10
-// CHECK:STDOUT:   if %.loc25_12 br !if.then.loc25 else br !if.else.loc25
+// CHECK:STDOUT:   %.loc25_12.1: bool = value_of_initializer %.loc25_10
+// CHECK:STDOUT:   %.loc25_12.2: bool = converted %.loc25_10, %.loc25_12.1
+// CHECK:STDOUT:   if %.loc25_12.2 br !if.then.loc25 else br !if.else.loc25
 // CHECK:STDOUT:
 // CHECK:STDOUT: !if.then.loc25:
 // CHECK:STDOUT:   br !while.done.loc17

+ 3 - 2
toolchain/check/testdata/while/unreachable_end.carbon

@@ -48,8 +48,9 @@ fn While() {
 // CHECK:STDOUT: !while.cond:
 // CHECK:STDOUT:   %Cond.ref: <function> = name_reference Cond, file.%Cond
 // CHECK:STDOUT:   %.loc15_14: init bool = call %Cond.ref()
-// CHECK:STDOUT:   %.loc15_16: bool = value_of_initializer %.loc15_14
-// CHECK:STDOUT:   if %.loc15_16 br !while.body else br !while.done
+// CHECK:STDOUT:   %.loc15_16.1: bool = value_of_initializer %.loc15_14
+// CHECK:STDOUT:   %.loc15_16.2: bool = converted %.loc15_14, %.loc15_16.1
+// CHECK:STDOUT:   if %.loc15_16.2 br !while.body else br !while.done
 // CHECK:STDOUT:
 // CHECK:STDOUT: !while.body:
 // CHECK:STDOUT:   %G.ref: <function> = name_reference G, file.%G

+ 3 - 2
toolchain/check/testdata/while/while.carbon

@@ -47,8 +47,9 @@ fn While() {
 // CHECK:STDOUT: !while.cond:
 // CHECK:STDOUT:   %Cond.ref: <function> = name_reference Cond, file.%Cond
 // CHECK:STDOUT:   %.loc15_14: init bool = call %Cond.ref()
-// CHECK:STDOUT:   %.loc15_16: bool = value_of_initializer %.loc15_14
-// CHECK:STDOUT:   if %.loc15_16 br !while.body else br !while.done
+// CHECK:STDOUT:   %.loc15_16.1: bool = value_of_initializer %.loc15_14
+// CHECK:STDOUT:   %.loc15_16.2: bool = converted %.loc15_14, %.loc15_16.1
+// CHECK:STDOUT:   if %.loc15_16.2 br !while.body else br !while.done
 // CHECK:STDOUT:
 // CHECK:STDOUT: !while.body:
 // CHECK:STDOUT:   %G.ref: <function> = name_reference G, file.%G

+ 18 - 0
toolchain/lower/file_context.cpp

@@ -56,6 +56,24 @@ auto FileContext::Run() -> std::unique_ptr<llvm::Module> {
   return std::move(llvm_module_);
 }
 
+auto FileContext::GetGlobal(SemIR::InstId inst_id) -> llvm::Value* {
+  // All builtins are types, with the same empty lowered value.
+  if (inst_id.index < SemIR::BuiltinKind::ValidCount) {
+    return GetTypeAsValue();
+  }
+
+  auto target = sem_ir().insts().Get(inst_id);
+  if (auto function_decl = target.TryAs<SemIR::FunctionDeclaration>()) {
+    return GetFunction(function_decl->function_id);
+  }
+
+  if (target.type_id() == SemIR::TypeId::TypeType) {
+    return GetTypeAsValue();
+  }
+
+  CARBON_FATAL() << "Missing value: " << inst_id << " " << target;
+}
+
 auto FileContext::BuildFunctionDeclaration(SemIR::FunctionId function_id)
     -> llvm::Function* {
   const auto& function = sem_ir().functions().Get(function_id);

+ 6 - 0
toolchain/lower/file_context.h

@@ -46,6 +46,9 @@ class FileContext {
     return llvm::ConstantStruct::get(GetTypeType());
   }
 
+  // Returns a global value for the given instruction.
+  auto GetGlobal(SemIR::InstId inst_id) -> llvm::Value*;
+
   auto llvm_context() -> llvm::LLVMContext& { return *llvm_context_; }
   auto llvm_module() -> llvm::Module& { return *llvm_module_; }
   auto sem_ir() -> const SemIR::File& { return *sem_ir_; }
@@ -92,6 +95,9 @@ class FileContext {
 
   // Lowered version of the builtin type `type`.
   llvm::StructType* type_type_ = nullptr;
+
+  // Maps global instructions to their lowered values.
+  llvm::DenseMap<SemIR::InstId, llvm::Value*> globals_;
 };
 
 }  // namespace Carbon::Lower

+ 2 - 14
toolchain/lower/function_context.cpp

@@ -78,18 +78,6 @@ auto FunctionContext::CreateSyntheticBlock() -> llvm::BasicBlock* {
   return synthetic_block_;
 }
 
-auto FunctionContext::GetLocalOrGlobal(SemIR::InstId inst_id) -> llvm::Value* {
-  auto target = sem_ir().insts().Get(inst_id);
-  if (auto function_decl = target.TryAs<SemIR::FunctionDeclaration>()) {
-    return GetFunction(function_decl->function_id);
-  }
-  if (auto class_type = target.TryAs<SemIR::ClassType>()) {
-    return GetTypeAsValue();
-  }
-  // TODO: Handle other kinds of name references to globals.
-  return GetLocal(inst_id);
-}
-
 auto FunctionContext::FinishInitialization(SemIR::TypeId type_id,
                                            SemIR::InstId dest_id,
                                            SemIR::InstId source_id) -> void {
@@ -112,7 +100,7 @@ auto FunctionContext::CopyValue(SemIR::TypeId type_id, SemIR::InstId source_id,
     case SemIR::ValueRepresentation::None:
       break;
     case SemIR::ValueRepresentation::Copy:
-      builder().CreateStore(GetLocal(source_id), GetLocal(dest_id));
+      builder().CreateStore(GetValue(source_id), GetValue(dest_id));
       break;
     case SemIR::ValueRepresentation::Pointer: {
       const auto& layout = llvm_module().getDataLayout();
@@ -123,7 +111,7 @@ auto FunctionContext::CopyValue(SemIR::TypeId type_id, SemIR::InstId source_id,
 
       // TODO: Attach !tbaa.struct metadata indicating which portions of the
       // type we actually need to copy and which are padding.
-      builder().CreateMemCpy(GetLocal(dest_id), align, GetLocal(source_id),
+      builder().CreateMemCpy(GetValue(dest_id), align, GetValue(source_id),
                              align, layout.getTypeAllocSize(type));
       break;
     }

+ 6 - 10
toolchain/lower/function_context.h

@@ -39,17 +39,18 @@ class FunctionContext {
   auto GetBlockArg(SemIR::InstBlockId block_id, SemIR::TypeId type_id)
       -> llvm::PHINode*;
 
-  // Returns a local (versus global) value for the given instruction.
-  auto GetLocal(SemIR::InstId inst_id) -> llvm::Value* {
+  // Returns a value for the given instruction.
+  auto GetValue(SemIR::InstId inst_id) -> llvm::Value* {
     // All builtins are types, with the same empty lowered value.
     if (inst_id.index < SemIR::BuiltinKind::ValidCount) {
       return GetTypeAsValue();
     }
 
     auto it = locals_.find(inst_id);
-    CARBON_CHECK(it != locals_.end())
-        << "Missing local: " << inst_id << " " << sem_ir().insts().Get(inst_id);
-    return it->second;
+    if (it != locals_.end()) {
+      return it->second;
+    }
+    return file_context_->GetGlobal(inst_id);
   }
 
   // Sets the value for the given instruction.
@@ -59,9 +60,6 @@ class FunctionContext {
                         << sem_ir().insts().Get(inst_id);
   }
 
-  // Returns a value for the given instruction, which might not be local.
-  auto GetLocalOrGlobal(SemIR::InstId inst_id) -> llvm::Value*;
-
   // Gets a callable's function.
   auto GetFunction(SemIR::FunctionId function_id) -> llvm::Function* {
     return file_context_->GetFunction(function_id);
@@ -128,8 +126,6 @@ class FunctionContext {
   llvm::BasicBlock* synthetic_block_ = nullptr;
 
   // Maps a function's SemIR::File instructions to lowered values.
-  // TODO: Handle nested scopes. Right now this is just cleared at the end of
-  // every block.
   llvm::DenseMap<SemIR::InstId, llvm::Value*> locals_;
 };
 

+ 21 - 20
toolchain/lower/handle.cpp

@@ -24,17 +24,17 @@ auto HandleCrossReference(FunctionContext& /*context*/,
 
 auto HandleAddressOf(FunctionContext& context, SemIR::InstId inst_id,
                      SemIR::AddressOf inst) -> void {
-  context.SetLocal(inst_id, context.GetLocal(inst.lvalue_id));
+  context.SetLocal(inst_id, context.GetValue(inst.lvalue_id));
 }
 
 auto HandleArrayIndex(FunctionContext& context, SemIR::InstId inst_id,
                       SemIR::ArrayIndex inst) -> void {
-  auto* array_value = context.GetLocal(inst.array_id);
+  auto* array_value = context.GetValue(inst.array_id);
   auto* llvm_type =
       context.GetType(context.sem_ir().insts().Get(inst.array_id).type_id());
   llvm::Value* indexes[2] = {
       llvm::ConstantInt::get(llvm::Type::getInt32Ty(context.llvm_context()), 0),
-      context.GetLocal(inst.index_id)};
+      context.GetValue(inst.index_id)};
   context.SetLocal(inst_id,
                    context.builder().CreateInBoundsGEP(llvm_type, array_value,
                                                        indexes, "array.index"));
@@ -43,11 +43,7 @@ auto HandleArrayIndex(FunctionContext& context, SemIR::InstId inst_id,
 auto HandleArrayInit(FunctionContext& context, SemIR::InstId inst_id,
                      SemIR::ArrayInit inst) -> void {
   // The result of initialization is the return slot of the initializer.
-  context.SetLocal(inst_id,
-                   context.GetLocal(context.sem_ir()
-                                        .inst_blocks()
-                                        .Get(inst.inits_and_return_slot_id)
-                                        .back()));
+  context.SetLocal(inst_id, context.GetValue(inst.dest_id));
 }
 
 auto HandleAssign(FunctionContext& context, SemIR::InstId /*inst_id*/,
@@ -64,7 +60,7 @@ auto HandleBinaryOperatorAdd(FunctionContext& /*context*/,
 
 auto HandleBindName(FunctionContext& context, SemIR::InstId inst_id,
                     SemIR::BindName inst) -> void {
-  context.SetLocal(inst_id, context.GetLocal(inst.value_id));
+  context.SetLocal(inst_id, context.GetValue(inst.value_id));
 }
 
 auto HandleBlockArg(FunctionContext& context, SemIR::InstId inst_id,
@@ -83,7 +79,7 @@ auto HandleBoundMethod(FunctionContext& context, SemIR::InstId inst_id,
                        SemIR::BoundMethod inst) -> void {
   // Propagate just the function; the object is separately provided to the
   // enclosing call as an implicit argument.
-  context.SetLocal(inst_id, context.GetLocalOrGlobal(inst.function_id));
+  context.SetLocal(inst_id, context.GetValue(inst.function_id));
 }
 
 auto HandleBranch(FunctionContext& context, SemIR::InstId /*inst_id*/,
@@ -102,7 +98,7 @@ auto HandleBranch(FunctionContext& context, SemIR::InstId /*inst_id*/,
 
 auto HandleBranchIf(FunctionContext& context, SemIR::InstId /*inst_id*/,
                     SemIR::BranchIf inst) -> void {
-  llvm::Value* cond = context.GetLocal(inst.cond_id);
+  llvm::Value* cond = context.GetValue(inst.cond_id);
   llvm::BasicBlock* then_block = context.GetBlock(inst.target_id);
   llvm::BasicBlock* else_block = context.CreateSyntheticBlock();
   context.builder().CreateCondBr(cond, then_block, else_block);
@@ -111,7 +107,7 @@ auto HandleBranchIf(FunctionContext& context, SemIR::InstId /*inst_id*/,
 
 auto HandleBranchWithArg(FunctionContext& context, SemIR::InstId /*inst_id*/,
                          SemIR::BranchWithArg inst) -> void {
-  llvm::Value* arg = context.GetLocal(inst.arg_id);
+  llvm::Value* arg = context.GetValue(inst.arg_id);
   SemIR::TypeId arg_type_id =
       context.sem_ir().insts().Get(inst.arg_id).type_id();
 
@@ -143,7 +139,7 @@ auto HandleBuiltin(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/,
 
 auto HandleCall(FunctionContext& context, SemIR::InstId inst_id,
                 SemIR::Call inst) -> void {
-  auto* callee = llvm::cast<llvm::Function>(context.GetLocal(inst.callee_id));
+  auto* callee = llvm::cast<llvm::Function>(context.GetValue(inst.callee_id));
 
   std::vector<llvm::Value*> args;
   llvm::ArrayRef<SemIR::InstId> arg_ids =
@@ -151,7 +147,7 @@ auto HandleCall(FunctionContext& context, SemIR::InstId inst_id,
 
   if (SemIR::GetInitializingRepresentation(context.sem_ir(), inst.type_id)
           .has_return_slot()) {
-    args.push_back(context.GetLocal(arg_ids.back()));
+    args.push_back(context.GetValue(arg_ids.back()));
     arg_ids = arg_ids.drop_back();
   }
 
@@ -159,7 +155,7 @@ auto HandleCall(FunctionContext& context, SemIR::InstId inst_id,
     auto arg_type_id = context.sem_ir().insts().Get(arg_id).type_id();
     if (SemIR::GetValueRepresentation(context.sem_ir(), arg_type_id).kind !=
         SemIR::ValueRepresentation::None) {
-      args.push_back(context.GetLocal(arg_id));
+      args.push_back(context.GetValue(arg_id));
     }
   }
 
@@ -173,9 +169,14 @@ auto HandleCall(FunctionContext& context, SemIR::InstId inst_id,
   }
 }
 
+auto HandleConverted(FunctionContext& context, SemIR::InstId inst_id,
+                     SemIR::Converted inst) -> void {
+  context.SetLocal(inst_id, context.GetValue(inst.result_id));
+}
+
 auto HandleDereference(FunctionContext& context, SemIR::InstId inst_id,
                        SemIR::Dereference inst) -> void {
-  context.SetLocal(inst_id, context.GetLocal(inst.pointer_id));
+  context.SetLocal(inst_id, context.GetValue(inst.pointer_id));
 }
 
 auto HandleFunctionDeclaration(FunctionContext& /*context*/,
@@ -209,7 +210,7 @@ auto HandleNameReference(FunctionContext& context, SemIR::InstId inst_id,
     return;
   }
 
-  context.SetLocal(inst_id, context.GetLocalOrGlobal(inst.value_id));
+  context.SetLocal(inst_id, context.GetValue(inst.value_id));
 }
 
 auto HandleNamespace(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/,
@@ -260,7 +261,7 @@ auto HandleReturnExpression(FunctionContext& context, SemIR::InstId /*inst_id*/,
       return;
     case SemIR::InitializingRepresentation::ByCopy:
       // The expression produces the value representation for the type.
-      context.builder().CreateRet(context.GetLocal(inst.expr_id));
+      context.builder().CreateRet(context.GetValue(inst.expr_id));
       return;
   }
 }
@@ -274,7 +275,7 @@ auto HandleSelfParameter(FunctionContext& /*context*/,
 auto HandleSpliceBlock(FunctionContext& context, SemIR::InstId inst_id,
                        SemIR::SpliceBlock inst) -> void {
   context.LowerBlock(inst.block_id);
-  context.SetLocal(inst_id, context.GetLocal(inst.result_id));
+  context.SetLocal(inst_id, context.GetValue(inst.result_id));
 }
 
 auto HandleStringLiteral(FunctionContext& /*context*/,
@@ -286,7 +287,7 @@ auto HandleStringLiteral(FunctionContext& /*context*/,
 auto HandleUnaryOperatorNot(FunctionContext& context, SemIR::InstId inst_id,
                             SemIR::UnaryOperatorNot inst) -> void {
   context.SetLocal(
-      inst_id, context.builder().CreateNot(context.GetLocal(inst.operand_id)));
+      inst_id, context.builder().CreateNot(context.GetValue(inst.operand_id)));
 }
 
 auto HandleVarStorage(FunctionContext& context, SemIR::InstId inst_id,

+ 4 - 4
toolchain/lower/handle_aggregates.cpp

@@ -28,7 +28,7 @@ static auto GetAggregateElement(FunctionContext& context,
                                 SemIR::TypeId result_type_id, llvm::Twine name)
     -> llvm::Value* {
   auto aggr_inst = context.sem_ir().insts().Get(aggr_inst_id);
-  auto* aggr_value = context.GetLocal(aggr_inst_id);
+  auto* aggr_value = context.GetValue(aggr_inst_id);
 
   switch (SemIR::GetExpressionCategory(context.sem_ir(), aggr_inst_id)) {
     case SemIR::ExpressionCategory::Error:
@@ -146,7 +146,7 @@ static auto EmitAggregateInitializer(FunctionContext& context,
       // TODO: Remove the LLVM StructType wrapper in this case, so we don't
       // need this `insert_value` wrapping.
       return context.builder().CreateInsertValue(
-          llvm::PoisonValue::get(llvm_type), context.GetLocal(refs[0]), {0},
+          llvm::PoisonValue::get(llvm_type), context.GetValue(refs[0]), {0},
           name);
     }
   }
@@ -203,7 +203,7 @@ auto EmitAggregateValueRepresentation(FunctionContext& context,
       // need this `insert_value` wrapping.
       return context.builder().CreateInsertValue(
           llvm::PoisonValue::get(context.GetType(value_rep.type_id)),
-          context.GetLocal(refs[0]), {0});
+          context.GetValue(refs[0]), {0});
     }
 
     case SemIR::ValueRepresentation::Pointer: {
@@ -218,7 +218,7 @@ auto EmitAggregateValueRepresentation(FunctionContext& context,
       for (auto [i, ref] :
            llvm::enumerate(context.sem_ir().inst_blocks().Get(refs_id))) {
         context.builder().CreateStore(
-            context.GetLocal(ref),
+            context.GetValue(ref),
             context.builder().CreateStructGEP(llvm_value_rep_type, alloca, i));
       }
       return alloca;

+ 5 - 5
toolchain/lower/handle_expression_category.cpp

@@ -25,10 +25,10 @@ auto HandleBindValue(FunctionContext& context, SemIR::InstId inst_id,
     case SemIR::ValueRepresentation::Copy:
       context.SetLocal(inst_id, context.builder().CreateLoad(
                                     context.GetType(inst.type_id),
-                                    context.GetLocal(inst.value_id)));
+                                    context.GetValue(inst.value_id)));
       break;
     case SemIR::ValueRepresentation::Pointer:
-      context.SetLocal(inst_id, context.GetLocal(inst.value_id));
+      context.SetLocal(inst_id, context.GetValue(inst.value_id));
       break;
     case SemIR::ValueRepresentation::Custom:
       CARBON_FATAL() << "TODO: Add support for BindValue with custom value rep";
@@ -38,7 +38,7 @@ auto HandleBindValue(FunctionContext& context, SemIR::InstId inst_id,
 auto HandleTemporary(FunctionContext& context, SemIR::InstId inst_id,
                      SemIR::Temporary inst) -> void {
   context.FinishInitialization(inst.type_id, inst.storage_id, inst.init_id);
-  context.SetLocal(inst_id, context.GetLocal(inst.storage_id));
+  context.SetLocal(inst_id, context.GetValue(inst.storage_id));
 }
 
 auto HandleTemporaryStorage(FunctionContext& context, SemIR::InstId inst_id,
@@ -55,7 +55,7 @@ auto HandleValueAsReference(FunctionContext& context, SemIR::InstId inst_id,
   CARBON_CHECK(
       SemIR::GetValueRepresentation(context.sem_ir(), inst.type_id).kind ==
       SemIR::ValueRepresentation::Pointer);
-  context.SetLocal(inst_id, context.GetLocal(inst.value_id));
+  context.SetLocal(inst_id, context.GetValue(inst.value_id));
 }
 
 auto HandleValueOfInitializer(FunctionContext& context, SemIR::InstId inst_id,
@@ -68,7 +68,7 @@ auto HandleValueOfInitializer(FunctionContext& context, SemIR::InstId inst_id,
   CARBON_CHECK(
       SemIR::GetInitializingRepresentation(context.sem_ir(), inst.type_id)
           .kind == SemIR::InitializingRepresentation::ByCopy);
-  context.SetLocal(inst_id, context.GetLocal(inst.init_id));
+  context.SetLocal(inst_id, context.GetValue(inst.init_id));
 }
 
 }  // namespace Carbon::Lower

+ 21 - 16
toolchain/lower/testdata/array/base.carbon

@@ -25,25 +25,30 @@ fn Run() {
 // CHECK:STDOUT:   %array.index2 = getelementptr inbounds [2 x double], ptr %b, i32 0, i32 1
 // CHECK:STDOUT:   store double 2.200000e+00, ptr %array.index2, align 8
 // CHECK:STDOUT:   %c = alloca [5 x {}], align 8
+// CHECK:STDOUT:   %array.index3 = getelementptr inbounds [5 x {}], ptr %c, i32 0, i32 0
+// CHECK:STDOUT:   %array.index4 = getelementptr inbounds [5 x {}], ptr %c, i32 0, i32 1
+// CHECK:STDOUT:   %array.index5 = getelementptr inbounds [5 x {}], ptr %c, i32 0, i32 2
+// CHECK:STDOUT:   %array.index6 = getelementptr inbounds [5 x {}], ptr %c, i32 0, i32 3
+// CHECK:STDOUT:   %array.index7 = getelementptr inbounds [5 x {}], ptr %c, i32 0, i32 4
 // CHECK:STDOUT:   %d = alloca { i32, i32, i32 }, align 8
 // CHECK:STDOUT:   %tuple.elem = getelementptr inbounds { i32, i32, i32 }, ptr %d, i32 0, i32 0
 // CHECK:STDOUT:   store i32 1, ptr %tuple.elem, align 4
-// CHECK:STDOUT:   %tuple.elem3 = getelementptr inbounds { i32, i32, i32 }, ptr %d, i32 0, i32 1
-// CHECK:STDOUT:   store i32 2, ptr %tuple.elem3, align 4
-// CHECK:STDOUT:   %tuple.elem4 = getelementptr inbounds { i32, i32, i32 }, ptr %d, i32 0, i32 2
-// CHECK:STDOUT:   store i32 3, ptr %tuple.elem4, align 4
-// CHECK:STDOUT:   %e = alloca [3 x i32], align 4
-// CHECK:STDOUT:   %tuple.elem5 = getelementptr inbounds { i32, i32, i32 }, ptr %d, i32 0, i32 0
-// CHECK:STDOUT:   %1 = load i32, ptr %tuple.elem5, align 4
-// CHECK:STDOUT:   %array.index6 = getelementptr inbounds [3 x i32], ptr %e, i32 0, i32 0
-// CHECK:STDOUT:   store i32 %1, ptr %array.index6, align 4
-// CHECK:STDOUT:   %tuple.elem7 = getelementptr inbounds { i32, i32, i32 }, ptr %d, i32 0, i32 1
-// CHECK:STDOUT:   %2 = load i32, ptr %tuple.elem7, align 4
-// CHECK:STDOUT:   %array.index8 = getelementptr inbounds [3 x i32], ptr %e, i32 0, i32 1
-// CHECK:STDOUT:   store i32 %2, ptr %array.index8, align 4
+// CHECK:STDOUT:   %tuple.elem8 = getelementptr inbounds { i32, i32, i32 }, ptr %d, i32 0, i32 1
+// CHECK:STDOUT:   store i32 2, ptr %tuple.elem8, align 4
 // CHECK:STDOUT:   %tuple.elem9 = getelementptr inbounds { i32, i32, i32 }, ptr %d, i32 0, i32 2
-// CHECK:STDOUT:   %3 = load i32, ptr %tuple.elem9, align 4
-// CHECK:STDOUT:   %array.index10 = getelementptr inbounds [3 x i32], ptr %e, i32 0, i32 2
-// CHECK:STDOUT:   store i32 %3, ptr %array.index10, align 4
+// CHECK:STDOUT:   store i32 3, ptr %tuple.elem9, align 4
+// CHECK:STDOUT:   %e = alloca [3 x i32], align 4
+// CHECK:STDOUT:   %tuple.elem10 = getelementptr inbounds { i32, i32, i32 }, ptr %d, i32 0, i32 0
+// CHECK:STDOUT:   %1 = load i32, ptr %tuple.elem10, align 4
+// CHECK:STDOUT:   %array.index11 = getelementptr inbounds [3 x i32], ptr %e, i32 0, i32 0
+// CHECK:STDOUT:   store i32 %1, ptr %array.index11, align 4
+// CHECK:STDOUT:   %tuple.elem12 = getelementptr inbounds { i32, i32, i32 }, ptr %d, i32 0, i32 1
+// CHECK:STDOUT:   %2 = load i32, ptr %tuple.elem12, align 4
+// CHECK:STDOUT:   %array.index13 = getelementptr inbounds [3 x i32], ptr %e, i32 0, i32 1
+// CHECK:STDOUT:   store i32 %2, ptr %array.index13, align 4
+// CHECK:STDOUT:   %tuple.elem14 = getelementptr inbounds { i32, i32, i32 }, ptr %d, i32 0, i32 2
+// CHECK:STDOUT:   %3 = load i32, ptr %tuple.elem14, align 4
+// CHECK:STDOUT:   %array.index15 = getelementptr inbounds [3 x i32], ptr %e, i32 0, i32 2
+// CHECK:STDOUT:   store i32 %3, ptr %array.index15, align 4
 // CHECK:STDOUT:   ret void
 // CHECK:STDOUT: }

+ 7 - 0
toolchain/sem_ir/file.cpp

@@ -199,6 +199,7 @@ static auto GetTypePrecedence(InstKind kind) -> int {
     case ClassDeclaration::Kind:
     case ClassFieldAccess::Kind:
     case ClassInit::Kind:
+    case Converted::Kind:
     case Dereference::Kind:
     case Field::Kind:
     case FunctionDeclaration::Kind:
@@ -401,6 +402,7 @@ auto File::StringifyTypeExpression(InstId outer_inst_id,
       case ClassDeclaration::Kind:
       case ClassFieldAccess::Kind:
       case ClassInit::Kind:
+      case Converted::Kind:
       case CrossReference::Kind:
       case Dereference::Kind:
       case Field::Kind:
@@ -492,6 +494,11 @@ auto GetExpressionCategory(const File& file, InstId inst_id)
         continue;
       }
 
+      case Converted::Kind: {
+        inst_id = inst.As<Converted>().result_id;
+        continue;
+      }
+
       case AddressOf::Kind:
       case ArrayType::Kind:
       case BinaryOperatorAdd::Kind:

+ 22 - 21
toolchain/sem_ir/formatter.cpp

@@ -141,7 +141,9 @@ class InstNamer {
     auto& [inst_scope, inst_name] = insts[inst_id.index];
     if (!inst_name) {
       // This should not happen in valid IR.
-      return "<unexpected instref " + llvm::itostr(inst_id.index) + ">";
+      std::string str;
+      llvm::raw_string_ostream(str) << "<unexpected instref " << inst_id << ">";
+      return str;
     }
     if (inst_scope == scope_idx) {
       return inst_name.str().str();
@@ -158,7 +160,10 @@ class InstNamer {
     auto& [label_scope, label_name] = labels[block_id.index];
     if (!label_name) {
       // This should not happen in valid IR.
-      return "<unexpected instblockref " + llvm::itostr(block_id.index) + ">";
+      std::string str;
+      llvm::raw_string_ostream(str)
+          << "<unexpected instblockref " << block_id << ">";
+      return str;
     }
     if (label_scope == scope_idx) {
       return label_name.str().str();
@@ -744,25 +749,6 @@ class Formatter {
     in_terminator_sequence_ = false;
   }
 
-  auto FormatInstructionRHS(ArrayInit inst) -> void {
-    out_ << " ";
-    FormatArg(inst.tuple_id);
-
-    llvm::ArrayRef<InstId> inits_and_return_slot =
-        sem_ir_.inst_blocks().Get(inst.inits_and_return_slot_id);
-    auto inits = inits_and_return_slot.drop_back(1);
-    auto return_slot_id = inits_and_return_slot.back();
-
-    out_ << ", (";
-    llvm::ListSeparator sep;
-    for (auto inst_id : inits) {
-      out_ << sep;
-      FormatArg(inst_id);
-    }
-    out_ << ')';
-    FormatReturnSlot(return_slot_id);
-  }
-
   auto FormatInstructionRHS(Call inst) -> void {
     out_ << " ";
     FormatArg(inst.callee_id);
@@ -795,11 +781,26 @@ class Formatter {
     }
   }
 
+  auto FormatInstructionRHS(ArrayInit inst) -> void {
+    FormatArgs(inst.inits_id);
+    FormatReturnSlot(inst.dest_id);
+  }
+
   auto FormatInstructionRHS(InitializeFrom inst) -> void {
     FormatArgs(inst.src_id);
     FormatReturnSlot(inst.dest_id);
   }
 
+  auto FormatInstructionRHS(StructInit init) -> void {
+    FormatArgs(init.elements_id);
+    FormatReturnSlot(init.dest_id);
+  }
+
+  auto FormatInstructionRHS(TupleInit init) -> void {
+    FormatArgs(init.elements_id);
+    FormatReturnSlot(init.dest_id);
+  }
+
   auto FormatInstructionRHS(CrossReference inst) -> void {
     // TODO: Figure out a way to make this meaningful. We'll need some way to
     // name cross-reference IRs, perhaps by the instruction ID of the import?

Некоторые файлы не были показаны из-за большого количества измененных файлов