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

Convert the scrutinee of a binding pattern to the right category. (#5662)

When the binding pattern appears within a `var` pattern, convert to a
reference. Otherwise, convert to a value.

This gets the advent of code examples to produce the right answers again
:)

---------

Co-authored-by: Geoff Romer <gromer@google.com>
Richard Smith 10 месяцев назад
Родитель
Сommit
80529aaef9
29 измененных файлов с 317 добавлено и 260 удалено
  1. 21 0
      toolchain/check/convert.cpp
  2. 2 0
      toolchain/check/convert.h
  3. 55 22
      toolchain/check/pattern_match.cpp
  4. 2 1
      toolchain/check/testdata/alias/basics.carbon
  5. 7 6
      toolchain/check/testdata/as/adapter_conversion.carbon
  6. 3 2
      toolchain/check/testdata/as/basics.carbon
  7. 9 9
      toolchain/check/testdata/builtins/int/convert_checked.carbon
  8. 6 6
      toolchain/check/testdata/builtins/read/char.carbon
  9. 6 5
      toolchain/check/testdata/class/access_modifers.carbon
  10. 13 11
      toolchain/check/testdata/class/adapter/init_adapt.carbon
  11. 4 2
      toolchain/check/testdata/class/derived_to_base.carbon
  12. 4 3
      toolchain/check/testdata/class/field_access_in_value.carbon
  13. 6 6
      toolchain/check/testdata/class/generic/base_is_generic.carbon
  14. 9 11
      toolchain/check/testdata/class/nested.carbon
  15. 3 2
      toolchain/check/testdata/deduce/value_with_type_through_access.carbon
  16. 5 4
      toolchain/check/testdata/facet/convert_facet_value_as_type_knows_original_type.carbon
  17. 3 2
      toolchain/check/testdata/facet/fail_deduction_uses_runtime_type_conversion.carbon
  18. 3 2
      toolchain/check/testdata/function/generic/type_param.carbon
  19. 3 2
      toolchain/check/testdata/impl/extend_impl_generic.carbon
  20. 3 2
      toolchain/check/testdata/impl/use_assoc_const.carbon
  21. 3 3
      toolchain/check/testdata/interop/cpp/function_return.carbon
  22. 40 124
      toolchain/check/testdata/let/convert.carbon
  23. 24 21
      toolchain/check/testdata/operators/overloaded/index_with_prelude.carbon
  24. 7 2
      toolchain/check/testdata/var/var_pattern.carbon
  25. 7 0
      toolchain/diagnostics/coverage_test.cpp
  26. 1 0
      toolchain/diagnostics/diagnostic_kind.def
  27. 4 8
      toolchain/lower/testdata/class/method.carbon
  28. 0 4
      toolchain/lower/testdata/function/generic/call_different_impls_with_const.carbon
  29. 64 0
      toolchain/lower/testdata/let/copy_value_rep.carbon

+ 21 - 0
toolchain/check/convert.cpp

@@ -696,6 +696,8 @@ static auto IsValidExprCategoryForConversionTarget(
              category == SemIR::ExprCategory::DurableRef ||
              category == SemIR::ExprCategory::EphemeralRef ||
              category == SemIR::ExprCategory::Initializing;
+    case ConversionTarget::DurableRef:
+      return category == SemIR::ExprCategory::DurableRef;
     case ConversionTarget::ExplicitAs:
       return true;
     case ConversionTarget::Initializer:
@@ -1340,12 +1342,19 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
       // Commit to using a temporary for this initializing expression.
       // TODO: Don't create a temporary if the initializing representation
       // is already a value representation.
+      // TODO: If the target is DurableRef, materialize a VarStorage instead of
+      // a TemporaryStorage to lifetime-extend.
       expr_id = FinalizeTemporary(context, expr_id,
                                   target.kind == ConversionTarget::Discarded);
       // We now have an ephemeral reference.
       [[fallthrough]];
 
     case SemIR::ExprCategory::DurableRef:
+      if (target.kind == ConversionTarget::DurableRef) {
+        break;
+      }
+      [[fallthrough]];
+
     case SemIR::ExprCategory::EphemeralRef:
       // If a reference expression is an acceptable result, we're done.
       if (target.kind == ConversionTarget::ValueOrRef ||
@@ -1362,6 +1371,18 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
       [[fallthrough]];
 
     case SemIR::ExprCategory::Value:
+      if (target.kind == ConversionTarget::DurableRef) {
+        if (target.diagnose) {
+          CARBON_DIAGNOSTIC(ConversionFailureNonRefToRef, Error,
+                            "cannot bind durable reference to non-reference "
+                            "value of type {0}",
+                            SemIR::TypeId);
+          context.emitter().Emit(loc_id, ConversionFailureNonRefToRef,
+                                 target.type_id);
+        }
+        return SemIR::ErrorInst::InstId;
+      }
+
       // When initializing from a value, perform a copy.
       if (target.is_initializer()) {
         expr_id = PerformCopy(context, expr_id, target.diagnose);

+ 2 - 0
toolchain/check/convert.h

@@ -19,6 +19,8 @@ struct ConversionTarget {
     Value,
     // Convert to either a value or a reference of type `type_id`.
     ValueOrRef,
+    // Convert to a durable reference of type `type_id`.
+    DurableRef,
     // Convert for an explicit `as` cast. This allows any expression category
     // as the result, and uses the `As` interface instead of the `ImplicitAs`
     // interface.

+ 55 - 22
toolchain/check/pattern_match.cpp

@@ -48,10 +48,13 @@ class MatchContext {
     SemIR::InstId pattern_id;
     // `None` when processing the callee side.
     SemIR::InstId scrutinee_id;
+    // Whether we are in a context where plain bindings are reference bindings.
+    // This happens in var patterns.
+    bool ref_binding_context;
 
     auto Print(llvm::raw_ostream& out) const -> void {
       out << "{pattern_id: " << pattern_id << ", scrutinee_id: " << scrutinee_id
-          << "}";
+          << ", ref_binding_context: " << ref_binding_context << "}";
     }
   };
 
@@ -224,10 +227,18 @@ auto MatchContext::DoEmitPatternMatch(Context& context,
   InsertHere(context, type_expr_region_id);
   auto value_id = SemIR::InstId::None;
   if (kind_ == MatchKind::Local) {
+    auto conversion_kind = entry.ref_binding_context
+                               ? ConversionTarget::DurableRef
+                               : ConversionTarget::Value;
+    if (!bind_name_id.has_value()) {
+      // TODO: Is this appropriate, or should we perform a conversion based on
+      // whether the `_` binding is a value or ref binding first, and then
+      // separately discard the initializer for a `_` binding?
+      conversion_kind = ConversionTarget::Discarded;
+    }
     value_id =
         Convert(context, SemIR::LocId(entry.scrutinee_id), entry.scrutinee_id,
-                {.kind = bind_name_id.has_value() ? ConversionTarget::ValueOrRef
-                                                  : ConversionTarget::Discarded,
+                {.kind = conversion_kind,
                  .type_id = context.insts().Get(bind_name_id).type_id()});
   } else {
     // In a function call, conversion is handled while matching the enclosing
@@ -253,7 +264,8 @@ auto MatchContext::DoEmitPatternMatch(Context& context,
     // the caller side of the pattern, so we traverse without emitting any
     // insts.
     AddWork({.pattern_id = addr_pattern.inner_id,
-             .scrutinee_id = SemIR::InstId::None});
+             .scrutinee_id = SemIR::InstId::None,
+             .ref_binding_context = false});
     return;
   }
   CARBON_CHECK(entry.scrutinee_id.has_value());
@@ -279,13 +291,16 @@ auto MatchContext::DoEmitPatternMatch(Context& context,
       context, SemIR::LocId(scrutinee_ref_id),
       {.type_id = GetPointerType(context, scrutinee_ref_type_inst_id),
        .lvalue_id = scrutinee_ref_id});
-  AddWork({.pattern_id = addr_pattern.inner_id, .scrutinee_id = new_scrutinee});
+  AddWork({.pattern_id = addr_pattern.inner_id,
+           .scrutinee_id = new_scrutinee,
+           .ref_binding_context = false});
 }
 
 auto MatchContext::DoEmitPatternMatch(Context& context,
                                       SemIR::ValueParamPattern param_pattern,
                                       SemIR::InstId pattern_inst_id,
                                       WorkItem entry) -> void {
+  CARBON_CHECK(!entry.ref_binding_context);
   switch (kind_) {
     case MatchKind::Caller: {
       CARBON_CHECK(
@@ -320,7 +335,8 @@ auto MatchContext::DoEmitPatternMatch(Context& context,
            .pretty_name_id = SemIR::GetPrettyNameFromPatternId(
                context.sem_ir(), entry.pattern_id)});
       AddWork({.pattern_id = param_pattern.subpattern_id,
-               .scrutinee_id = param_id});
+               .scrutinee_id = param_id,
+               .ref_binding_context = entry.ref_binding_context});
       results_.push_back(param_id);
       break;
     }
@@ -334,6 +350,7 @@ auto MatchContext::DoEmitPatternMatch(Context& context,
                                       SemIR::RefParamPattern param_pattern,
                                       SemIR::InstId pattern_inst_id,
                                       WorkItem entry) -> void {
+  CARBON_CHECK(entry.ref_binding_context);
   switch (kind_) {
     case MatchKind::Caller: {
       CARBON_CHECK(
@@ -362,7 +379,8 @@ auto MatchContext::DoEmitPatternMatch(Context& context,
            .pretty_name_id = SemIR::GetPrettyNameFromPatternId(
                context.sem_ir(), entry.pattern_id)});
       AddWork({.pattern_id = param_pattern.subpattern_id,
-               .scrutinee_id = param_id});
+               .scrutinee_id = param_id,
+               .ref_binding_context = entry.ref_binding_context});
       results_.push_back(param_id);
       break;
     }
@@ -376,6 +394,7 @@ auto MatchContext::DoEmitPatternMatch(Context& context,
                                       SemIR::OutParamPattern param_pattern,
                                       SemIR::InstId pattern_inst_id,
                                       WorkItem entry) -> void {
+  CARBON_CHECK(!entry.ref_binding_context);
   switch (kind_) {
     case MatchKind::Caller: {
       CARBON_CHECK(
@@ -408,7 +427,8 @@ auto MatchContext::DoEmitPatternMatch(Context& context,
            .pretty_name_id = SemIR::GetPrettyNameFromPatternId(
                context.sem_ir(), entry.pattern_id)});
       AddWork({.pattern_id = param_pattern.subpattern_id,
-               .scrutinee_id = param_id});
+               .scrutinee_id = param_id,
+               .ref_binding_context = entry.ref_binding_context});
       results_.push_back(param_id);
       break;
     }
@@ -447,7 +467,8 @@ auto MatchContext::DoEmitPatternMatch(Context& context,
       // the caller side of the pattern, so we traverse without emitting any
       // insts.
       AddWork({.pattern_id = var_pattern.subpattern_id,
-               .scrutinee_id = SemIR::InstId::None});
+               .scrutinee_id = SemIR::InstId::None,
+               .ref_binding_context = true});
       return;
     }
     case MatchKind::Local: {
@@ -481,8 +502,9 @@ auto MatchContext::DoEmitPatternMatch(Context& context,
     AddInst<SemIR::Assign>(context, SemIR::LocId(pattern_inst_id),
                            {.lhs_id = storage_id, .rhs_id = init_id});
   }
-  AddWork(
-      {.pattern_id = var_pattern.subpattern_id, .scrutinee_id = storage_id});
+  AddWork({.pattern_id = var_pattern.subpattern_id,
+           .scrutinee_id = storage_id,
+           .ref_binding_context = true});
   if (context.scope_stack().PeekIndex() == ScopeIndex::Package) {
     context.global_init().Suspend();
   }
@@ -500,8 +522,9 @@ auto MatchContext::DoEmitPatternMatch(Context& context,
       [&](llvm::ArrayRef<SemIR::InstId> subscrutinee_ids) {
         for (auto [subpattern_id, subscrutinee_id] :
              llvm::reverse(llvm::zip(subpattern_ids, subscrutinee_ids))) {
-          AddWork(
-              {.pattern_id = subpattern_id, .scrutinee_id = subscrutinee_id});
+          AddWork({.pattern_id = subpattern_id,
+                   .scrutinee_id = subscrutinee_id,
+                   .ref_binding_context = entry.ref_binding_context});
         }
       };
   if (!entry.scrutinee_id.has_value()) {
@@ -627,22 +650,25 @@ auto CalleePatternMatch(Context& context,
   // in the original order.
   if (return_slot_pattern_id.has_value()) {
     match.AddWork({.pattern_id = return_slot_pattern_id,
-                   .scrutinee_id = SemIR::InstId::None});
+                   .scrutinee_id = SemIR::InstId::None,
+                   .ref_binding_context = false});
   }
 
   if (param_patterns_id.has_value()) {
     for (SemIR::InstId inst_id :
          llvm::reverse(context.inst_blocks().Get(param_patterns_id))) {
-      match.AddWork(
-          {.pattern_id = inst_id, .scrutinee_id = SemIR::InstId::None});
+      match.AddWork({.pattern_id = inst_id,
+                     .scrutinee_id = SemIR::InstId::None,
+                     .ref_binding_context = false});
     }
   }
 
   if (implicit_param_patterns_id.has_value()) {
     for (SemIR::InstId inst_id :
          llvm::reverse(context.inst_blocks().Get(implicit_param_patterns_id))) {
-      match.AddWork(
-          {.pattern_id = inst_id, .scrutinee_id = SemIR::InstId::None});
+      match.AddWork({.pattern_id = inst_id,
+                     .scrutinee_id = SemIR::InstId::None,
+                     .ref_binding_context = false});
     }
   }
 
@@ -663,17 +689,22 @@ auto CallerPatternMatch(Context& context, SemIR::SpecificId specific_id,
   if (return_slot_arg_id.has_value()) {
     CARBON_CHECK(return_slot_pattern_id.has_value());
     match.AddWork({.pattern_id = return_slot_pattern_id,
-                   .scrutinee_id = return_slot_arg_id});
+                   .scrutinee_id = return_slot_arg_id,
+                   .ref_binding_context = false});
   }
 
   // Check type conversions per-element.
   for (auto [arg_id, param_pattern_id] : llvm::reverse(llvm::zip_equal(
            arg_refs, context.inst_blocks().GetOrEmpty(param_patterns_id)))) {
-    match.AddWork({.pattern_id = param_pattern_id, .scrutinee_id = arg_id});
+    match.AddWork({.pattern_id = param_pattern_id,
+                   .scrutinee_id = arg_id,
+                   .ref_binding_context = false});
   }
 
   if (self_pattern_id.has_value()) {
-    match.AddWork({.pattern_id = self_pattern_id, .scrutinee_id = self_arg_id});
+    match.AddWork({.pattern_id = self_pattern_id,
+                   .scrutinee_id = self_arg_id,
+                   .ref_binding_context = false});
   }
 
   return match.DoWork(context);
@@ -682,7 +713,9 @@ auto CallerPatternMatch(Context& context, SemIR::SpecificId specific_id,
 auto LocalPatternMatch(Context& context, SemIR::InstId pattern_id,
                        SemIR::InstId scrutinee_id) -> void {
   MatchContext match(MatchKind::Local);
-  match.AddWork({.pattern_id = pattern_id, .scrutinee_id = scrutinee_id});
+  match.AddWork({.pattern_id = pattern_id,
+                 .scrutinee_id = scrutinee_id,
+                 .ref_binding_context = false});
   match.DoWork(context);
 }
 

+ 2 - 1
toolchain/check/testdata/alias/basics.carbon

@@ -187,7 +187,8 @@ extern alias C = Class;
 // CHECK:STDOUT:   %.loc10_13.2: init %C = class_init (), %.loc10_13.1 [concrete = constants.%C.val]
 // CHECK:STDOUT:   %.loc10_13.3: ref %C = temporary %.loc10_13.1, %.loc10_13.2
 // CHECK:STDOUT:   %.loc10_13.4: ref %C = converted @__global_init.%.loc10, %.loc10_13.3
-// CHECK:STDOUT:   %d: ref %C = bind_name d, %.loc10_13.4
+// CHECK:STDOUT:   %.loc10_13.5: %C = bind_value %.loc10_13.4
+// CHECK:STDOUT:   %d: %C = bind_name d, %.loc10_13.5
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {

+ 7 - 6
toolchain/check/testdata/as/adapter_conversion.carbon

@@ -182,9 +182,9 @@ var b: B = {.x = ()} as B;
 // CHECK:STDOUT:   %Make: %Make.type = struct_value () [concrete]
 // CHECK:STDOUT:   %B: type = class_type @B [concrete]
 // CHECK:STDOUT:   %pattern_type.049: type = pattern_type %B [concrete]
-// CHECK:STDOUT:   %a_ref.var: ref %B = var file.%a_ref.var_patt [concrete]
 // CHECK:STDOUT:   %ptr.e79: type = ptr_type %B [concrete]
 // CHECK:STDOUT:   %pattern_type.960: type = pattern_type %ptr.e79 [concrete]
+// CHECK:STDOUT:   %a_ref.var: ref %B = var file.%a_ref.var_patt [concrete]
 // CHECK:STDOUT:   %addr: %ptr.e79 = addr_of %a_ref.var [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -196,7 +196,7 @@ var b: B = {.x = ()} as B;
 // CHECK:STDOUT:     %b_val.patt: %pattern_type.049 = binding_pattern b_val [concrete]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %B.ref.loc22: type = name_ref B, %B.decl [concrete = constants.%B]
-// CHECK:STDOUT:   %b_val: ref %B = bind_name b_val, @__global_init.%.loc22_22.2 [concrete = constants.%a_ref.var]
+// CHECK:STDOUT:   %b_val: %B = bind_name b_val, @__global_init.%.loc22_22.2
 // CHECK:STDOUT:   name_binding_decl {
 // CHECK:STDOUT:     %b_ptr.patt: %pattern_type.960 = binding_pattern b_ptr [concrete]
 // CHECK:STDOUT:   }
@@ -217,10 +217,10 @@ var b: B = {.x = ()} as B;
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   <elided>
-// CHECK:STDOUT:   %a_val.ref: ref %A = name_ref a_val, file.%a_val [concrete = file.%a_ref.var]
+// CHECK:STDOUT:   %a_val.ref: %A = name_ref a_val, file.%a_val
 // CHECK:STDOUT:   %B.ref.loc22: type = name_ref B, file.%B.decl [concrete = constants.%B]
-// CHECK:STDOUT:   %.loc22_22.1: ref %B = as_compatible %a_val.ref [concrete = constants.%a_ref.var]
-// CHECK:STDOUT:   %.loc22_22.2: ref %B = converted %a_val.ref, %.loc22_22.1 [concrete = constants.%a_ref.var]
+// CHECK:STDOUT:   %.loc22_22.1: %B = as_compatible %a_val.ref
+// CHECK:STDOUT:   %.loc22_22.2: %B = converted %a_val.ref, %.loc22_22.1
 // CHECK:STDOUT:   %a_ref.ref.loc23: ref %A = name_ref a_ref, file.%a_ref [concrete = file.%a_ref.var]
 // CHECK:STDOUT:   %B.ref.loc23: type = name_ref B, file.%B.decl [concrete = constants.%B]
 // CHECK:STDOUT:   %.loc23_25.1: ref %B = as_compatible %a_ref.ref.loc23 [concrete = constants.%a_ref.var]
@@ -379,7 +379,8 @@ var b: B = {.x = ()} as B;
 // CHECK:STDOUT:     %b_value.patt: %pattern_type.049 = binding_pattern b_value [concrete]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %B.ref: type = name_ref B, %B.decl [concrete = constants.%B]
-// CHECK:STDOUT:   %b_value: ref %B = bind_name b_value, @__global_init.%.loc14_42.2
+// CHECK:STDOUT:   %.loc14: %B = bind_value @__global_init.%.loc14_42.2
+// CHECK:STDOUT:   %b_value: %B = bind_name b_value, %.loc14
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {

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

@@ -362,8 +362,9 @@ let n: {.x: ()} = {.x = ()} as {.x = ()};
 // CHECK:STDOUT:     %n.patt: %pattern_type.c27 = binding_pattern n [concrete]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Y.ref: type = name_ref Y, %Y.decl [concrete = constants.%Y]
-// CHECK:STDOUT:   %.loc19: ref %Y = temporary @__global_init.%.loc19_29.1, @__global_init.%.loc19_29.2
-// CHECK:STDOUT:   %n: ref %Y = bind_name n, %.loc19
+// CHECK:STDOUT:   %.loc19_29.1: ref %Y = temporary @__global_init.%.loc19_29.1, @__global_init.%.loc19_29.2
+// CHECK:STDOUT:   %.loc19_29.2: %Y = bind_value %.loc19_29.1
+// CHECK:STDOUT:   %n: %Y = bind_name n, %.loc19_29.2
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {

+ 9 - 9
toolchain/check/testdata/builtins/int/convert_checked.carbon

@@ -315,9 +315,9 @@ let convert_not_constant_widen: i64 = Int32ToInt64(not_constant);
 // CHECK:STDOUT:     %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
 // CHECK:STDOUT:     %u32: type = class_type @UInt, @UInt(constants.%int_32) [concrete = constants.%u32]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc6_42.1: ref %u32 = temporary_storage
-// CHECK:STDOUT:   %.loc6_42.2: ref %u32 = temporary %.loc6_42.1, @__global_init.%int.convert_checked.loc6_42
-// CHECK:STDOUT:   %SizePreserving: ref %u32 = bind_name SizePreserving, %.loc6_42.2
+// CHECK:STDOUT:   %.loc6_42.1: %u32 = value_of_initializer @__global_init.%int.convert_checked.loc6_42 [concrete = constants.%int_1.c1d]
+// CHECK:STDOUT:   %.loc6_42.2: %u32 = converted @__global_init.%int.convert_checked.loc6_42, %.loc6_42.1 [concrete = constants.%int_1.c1d]
+// CHECK:STDOUT:   %SizePreserving: %u32 = bind_name SizePreserving, %.loc6_42.2
 // CHECK:STDOUT:   name_binding_decl {
 // CHECK:STDOUT:     %Narrowing.patt: %pattern_type.88f = binding_pattern Narrowing [concrete]
 // CHECK:STDOUT:   }
@@ -325,9 +325,9 @@ let convert_not_constant_widen: i64 = Int32ToInt64(not_constant);
 // CHECK:STDOUT:     %int_16: Core.IntLiteral = int_value 16 [concrete = constants.%int_16]
 // CHECK:STDOUT:     %i16: type = class_type @Int, @Int(constants.%int_16) [concrete = constants.%i16]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc7_36.1: ref %i16 = temporary_storage
-// CHECK:STDOUT:   %.loc7_36.2: ref %i16 = temporary %.loc7_36.1, @__global_init.%int.convert_checked.loc7_36
-// CHECK:STDOUT:   %Narrowing: ref %i16 = bind_name Narrowing, %.loc7_36.2
+// CHECK:STDOUT:   %.loc7_36.1: %i16 = value_of_initializer @__global_init.%int.convert_checked.loc7_36 [concrete = constants.%int_1.c22]
+// CHECK:STDOUT:   %.loc7_36.2: %i16 = converted @__global_init.%int.convert_checked.loc7_36, %.loc7_36.1 [concrete = constants.%int_1.c22]
+// CHECK:STDOUT:   %Narrowing: %i16 = bind_name Narrowing, %.loc7_36.2
 // CHECK:STDOUT:   name_binding_decl {
 // CHECK:STDOUT:     %Widening.patt: %pattern_type.a10 = binding_pattern Widening [concrete]
 // CHECK:STDOUT:   }
@@ -335,9 +335,9 @@ let convert_not_constant_widen: i64 = Int32ToInt64(not_constant);
 // CHECK:STDOUT:     %int_64: Core.IntLiteral = int_value 64 [concrete = constants.%int_64]
 // CHECK:STDOUT:     %i64: type = class_type @Int, @Int(constants.%int_64) [concrete = constants.%i64]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc8_35.1: ref %i64 = temporary_storage
-// CHECK:STDOUT:   %.loc8_35.2: ref %i64 = temporary %.loc8_35.1, @__global_init.%int.convert_checked.loc8_35
-// CHECK:STDOUT:   %Widening: ref %i64 = bind_name Widening, %.loc8_35.2
+// CHECK:STDOUT:   %.loc8_35.1: %i64 = value_of_initializer @__global_init.%int.convert_checked.loc8_35 [concrete = constants.%int_1.a95]
+// CHECK:STDOUT:   %.loc8_35.2: %i64 = converted @__global_init.%int.convert_checked.loc8_35, %.loc8_35.1 [concrete = constants.%int_1.a95]
+// CHECK:STDOUT:   %Widening: %i64 = bind_name Widening, %.loc8_35.2
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {

+ 6 - 6
toolchain/check/testdata/builtins/read/char.carbon

@@ -58,9 +58,9 @@ fn Main() {
 // CHECK:STDOUT:     %int_32.loc8: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
 // CHECK:STDOUT:     %i32.loc8: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc8_25.1: ref %i32 = temporary_storage
-// CHECK:STDOUT:   %.loc8_25.2: ref %i32 = temporary %.loc8_25.1, %read.char.loc8
-// CHECK:STDOUT:   %n: ref %i32 = bind_name n, %.loc8_25.2
+// CHECK:STDOUT:   %.loc8_25.1: %i32 = value_of_initializer %read.char.loc8
+// CHECK:STDOUT:   %.loc8_25.2: %i32 = converted %read.char.loc8, %.loc8_25.1
+// CHECK:STDOUT:   %n: %i32 = bind_name n, %.loc8_25.2
 // CHECK:STDOUT:   name_binding_decl {
 // CHECK:STDOUT:     %m.patt: %pattern_type.7ce = binding_pattern m [concrete]
 // CHECK:STDOUT:   }
@@ -71,9 +71,9 @@ fn Main() {
 // CHECK:STDOUT:     %int_32.loc9: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
 // CHECK:STDOUT:     %i32.loc9: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc9_30.1: ref %i32 = temporary_storage
-// CHECK:STDOUT:   %.loc9_30.2: ref %i32 = temporary %.loc9_30.1, %read.char.loc9
-// CHECK:STDOUT:   %m: ref %i32 = bind_name m, %.loc9_30.2
+// CHECK:STDOUT:   %.loc9_30.1: %i32 = value_of_initializer %read.char.loc9
+// CHECK:STDOUT:   %.loc9_30.2: %i32 = converted %read.char.loc9, %.loc9_30.1
+// CHECK:STDOUT:   %m: %i32 = bind_name m, %.loc9_30.2
 // CHECK:STDOUT:   <elided>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 6 - 5
toolchain/check/testdata/class/access_modifers.carbon

@@ -307,24 +307,25 @@ class A {
 // CHECK:STDOUT:   %Make.call: init %Circle = call %Make.ref() to %.loc18_36.1
 // CHECK:STDOUT:   %Circle.ref.loc18_15: type = name_ref Circle, file.%Circle.decl [concrete = constants.%Circle]
 // CHECK:STDOUT:   %.loc18_36.2: ref %Circle = temporary %.loc18_36.1, %Make.call
-// CHECK:STDOUT:   %circle: ref %Circle = bind_name circle, %.loc18_36.2
+// CHECK:STDOUT:   %.loc18_36.3: %Circle = bind_value %.loc18_36.2
+// CHECK:STDOUT:   %circle: %Circle = bind_name circle, %.loc18_36.3
 // CHECK:STDOUT:   name_binding_decl {
 // CHECK:STDOUT:     %radius.patt: %pattern_type.7ce = binding_pattern radius [concrete]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %circle.ref.loc26: ref %Circle = name_ref circle, %circle
+// CHECK:STDOUT:   %circle.ref.loc26: %Circle = name_ref circle, %circle
 // CHECK:STDOUT:   %radius.ref.loc26: <error> = name_ref radius, <error> [concrete = <error>]
 // CHECK:STDOUT:   %.loc26: type = splice_block %i32 [concrete = constants.%i32] {
 // CHECK:STDOUT:     %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
 // CHECK:STDOUT:     %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %radius: %i32 = bind_name radius, <error> [concrete = <error>]
-// CHECK:STDOUT:   %circle.ref.loc34: ref %Circle = name_ref circle, %circle
+// CHECK:STDOUT:   %circle.ref.loc34: %Circle = name_ref circle, %circle
 // CHECK:STDOUT:   %radius.ref.loc34: <error> = name_ref radius, <error> [concrete = <error>]
 // CHECK:STDOUT:   %int_5: Core.IntLiteral = int_value 5 [concrete = constants.%int_5.64b]
 // CHECK:STDOUT:   assign %radius.ref.loc34, <error>
-// CHECK:STDOUT:   %circle.ref.loc42: ref %Circle = name_ref circle, %circle
+// CHECK:STDOUT:   %circle.ref.loc42: %Circle = name_ref circle, %circle
 // CHECK:STDOUT:   %SOME_INTERNAL_CONSTANT.ref: <error> = name_ref SOME_INTERNAL_CONSTANT, <error> [concrete = <error>]
-// CHECK:STDOUT:   %circle.ref.loc51: ref %Circle = name_ref circle, %circle
+// CHECK:STDOUT:   %circle.ref.loc51: %Circle = name_ref circle, %circle
 // CHECK:STDOUT:   %SomeInternalFunction.ref: <error> = name_ref SomeInternalFunction, <error> [concrete = <error>]
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }

+ 13 - 11
toolchain/check/testdata/class/adapter/init_adapt.carbon

@@ -191,17 +191,18 @@ var e: C = MakeAdaptC();
 // CHECK:STDOUT:   %.loc13_27.8: init %C = class_init (%.loc13_27.4, %.loc13_27.7), %.loc13_27.2 [concrete = constants.%C.val]
 // CHECK:STDOUT:   %.loc13_27.9: ref %C = temporary %.loc13_27.2, %.loc13_27.8
 // CHECK:STDOUT:   %.loc13_27.10: ref %C = converted @__global_init.%.loc13, %.loc13_27.9
-// CHECK:STDOUT:   %a: ref %C = bind_name a, %.loc13_27.10
+// CHECK:STDOUT:   %.loc13_27.11: %C = bind_value %.loc13_27.10
+// CHECK:STDOUT:   %a: %C = bind_name a, %.loc13_27.11
 // CHECK:STDOUT:   name_binding_decl {
 // CHECK:STDOUT:     %b.patt: %pattern_type.a1a = binding_pattern b [concrete]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %AdaptC.ref.loc15: type = name_ref AdaptC, %AdaptC.decl [concrete = constants.%AdaptC]
-// CHECK:STDOUT:   %b: ref %AdaptC = bind_name b, @__global_init.%.loc15_19.2
+// CHECK:STDOUT:   %b: %AdaptC = bind_name b, @__global_init.%.loc15_19.2
 // CHECK:STDOUT:   name_binding_decl {
 // CHECK:STDOUT:     %c.patt: %pattern_type.c48 = binding_pattern c [concrete]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %C.ref.loc17: type = name_ref C, %C.decl [concrete = constants.%C]
-// CHECK:STDOUT:   %c: ref %C = bind_name c, @__global_init.%.loc17_14.2
+// CHECK:STDOUT:   %c: %C = bind_name c, @__global_init.%.loc17_14.2
 // CHECK:STDOUT:   %MakeC.decl: %MakeC.type = fn_decl @MakeC [concrete = constants.%MakeC] {
 // CHECK:STDOUT:     %return.patt: %pattern_type.c48 = return_slot_pattern [concrete]
 // CHECK:STDOUT:     %return.param_patt: %pattern_type.c48 = out_param_pattern %return.patt, call_param0 [concrete]
@@ -271,14 +272,14 @@ var e: C = MakeAdaptC();
 // CHECK:STDOUT:   %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1.5b8]
 // CHECK:STDOUT:   %int_2: Core.IntLiteral = int_value 2 [concrete = constants.%int_2.ecc]
 // CHECK:STDOUT:   %.loc13: %struct_type.a.b.cfd = struct_literal (%int_1, %int_2)
-// CHECK:STDOUT:   %a.ref: ref %C = name_ref a, file.%a
+// CHECK:STDOUT:   %a.ref: %C = name_ref a, file.%a
 // CHECK:STDOUT:   %AdaptC.ref.loc15: type = name_ref AdaptC, file.%AdaptC.decl [concrete = constants.%AdaptC]
-// CHECK:STDOUT:   %.loc15_19.1: ref %AdaptC = as_compatible %a.ref
-// CHECK:STDOUT:   %.loc15_19.2: ref %AdaptC = converted %a.ref, %.loc15_19.1
-// CHECK:STDOUT:   %b.ref: ref %AdaptC = name_ref b, file.%b
+// CHECK:STDOUT:   %.loc15_19.1: %AdaptC = as_compatible %a.ref
+// CHECK:STDOUT:   %.loc15_19.2: %AdaptC = converted %a.ref, %.loc15_19.1
+// CHECK:STDOUT:   %b.ref: %AdaptC = name_ref b, file.%b
 // CHECK:STDOUT:   %C.ref.loc17: type = name_ref C, file.%C.decl [concrete = constants.%C]
-// CHECK:STDOUT:   %.loc17_14.1: ref %C = as_compatible %b.ref
-// CHECK:STDOUT:   %.loc17_14.2: ref %C = converted %b.ref, %.loc17_14.1
+// CHECK:STDOUT:   %.loc17_14.1: %C = as_compatible %b.ref
+// CHECK:STDOUT:   %.loc17_14.2: %C = converted %b.ref, %.loc17_14.1
 // CHECK:STDOUT:   %MakeC.ref: %MakeC.type = name_ref MakeC, file.%MakeC.decl [concrete = constants.%MakeC]
 // CHECK:STDOUT:   %.loc23_1: ref %AdaptC = splice_block file.%d.var [concrete = file.%d.var] {}
 // CHECK:STDOUT:   %MakeC.call: init %C = call %MakeC.ref() to %.loc23_1
@@ -392,7 +393,8 @@ var e: C = MakeAdaptC();
 // CHECK:STDOUT:   %.loc13_27.8: init %C = class_init (%.loc13_27.4, %.loc13_27.7), %.loc13_27.2 [concrete = constants.%C.val]
 // CHECK:STDOUT:   %.loc13_27.9: ref %C = temporary %.loc13_27.2, %.loc13_27.8
 // CHECK:STDOUT:   %.loc13_27.10: ref %C = converted @__global_init.%.loc13, %.loc13_27.9
-// CHECK:STDOUT:   %a: ref %C = bind_name a, %.loc13_27.10
+// CHECK:STDOUT:   %.loc13_27.11: %C = bind_value %.loc13_27.10
+// CHECK:STDOUT:   %a: %C = bind_name a, %.loc13_27.11
 // CHECK:STDOUT:   name_binding_decl {
 // CHECK:STDOUT:     %b.patt: %pattern_type.a1a = binding_pattern b [concrete]
 // CHECK:STDOUT:   }
@@ -474,7 +476,7 @@ var e: C = MakeAdaptC();
 // CHECK:STDOUT:   %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1.5b8]
 // CHECK:STDOUT:   %int_2: Core.IntLiteral = int_value 2 [concrete = constants.%int_2.ecc]
 // CHECK:STDOUT:   %.loc13: %struct_type.a.b.cfd = struct_literal (%int_1, %int_2)
-// CHECK:STDOUT:   %a.ref: ref %C = name_ref a, file.%a
+// CHECK:STDOUT:   %a.ref: %C = name_ref a, file.%a
 // CHECK:STDOUT:   %b.ref: %AdaptC = name_ref b, file.%b [concrete = <error>]
 // CHECK:STDOUT:   %MakeC.ref: %MakeC.type = name_ref MakeC, file.%MakeC.decl [concrete = constants.%MakeC]
 // CHECK:STDOUT:   %.loc46_23: ref %C = temporary_storage

+ 4 - 2
toolchain/check/testdata/class/derived_to_base.carbon

@@ -314,7 +314,8 @@ fn ConvertInit() {
 // CHECK:STDOUT:   %.loc33_14.1: ref %B = class_element_access %c.ref, element0
 // CHECK:STDOUT:   %.loc33_14.2: ref %A = class_element_access %.loc33_14.1, element0
 // CHECK:STDOUT:   %.loc33_14.3: ref %A = converted %c.ref, %.loc33_14.2
-// CHECK:STDOUT:   %a: ref %A = bind_name a, %.loc33_14.3
+// CHECK:STDOUT:   %.loc33_14.4: %A = bind_value %.loc33_14.3
+// CHECK:STDOUT:   %a: %A = bind_name a, %.loc33_14.4
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -380,7 +381,8 @@ fn ConvertInit() {
 // CHECK:STDOUT:   %.loc41_59.2: ref %B = class_element_access %.loc41_59.1, element0
 // CHECK:STDOUT:   %.loc41_59.3: ref %A = class_element_access %.loc41_59.2, element0
 // CHECK:STDOUT:   %.loc41_59.4: ref %A = converted %.loc41_59.1, %.loc41_59.3
-// CHECK:STDOUT:   %a: ref %A = bind_name a, %.loc41_59.4
+// CHECK:STDOUT:   %.loc41_59.5: %A = bind_value %.loc41_59.4
+// CHECK:STDOUT:   %a: %A = bind_name a, %.loc41_59.5
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 4 - 3
toolchain/check/testdata/class/field_access_in_value.carbon

@@ -140,13 +140,14 @@ fn Test() {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %cv.ref.loc23: ref %Class = name_ref cv, %cv
 // CHECK:STDOUT:   %Class.ref.loc23: type = name_ref Class, file.%Class.decl [concrete = constants.%Class]
-// CHECK:STDOUT:   %c: ref %Class = bind_name c, %cv.ref.loc23
+// CHECK:STDOUT:   %.loc23: %Class = bind_value %cv.ref.loc23
+// CHECK:STDOUT:   %c: %Class = bind_name c, %.loc23
 // CHECK:STDOUT:   name_binding_decl {
 // CHECK:STDOUT:     %cj.patt: %pattern_type.7ce = binding_pattern cj [concrete]
 // CHECK:STDOUT:     %cj.var_patt: %pattern_type.7ce = var_pattern %cj.patt [concrete]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %cj.var: ref %i32 = var %cj.var_patt
-// CHECK:STDOUT:   %c.ref.loc24: ref %Class = name_ref c, %c
+// CHECK:STDOUT:   %c.ref.loc24: %Class = name_ref c, %c
 // CHECK:STDOUT:   %j.ref.loc24: %Class.elem = name_ref j, @Class.%.loc15 [concrete = @Class.%.loc15]
 // CHECK:STDOUT:   %.loc24_18.1: ref %i32 = class_element_access %c.ref.loc24, element0
 // CHECK:STDOUT:   %.loc24_18.2: %i32 = bind_value %.loc24_18.1
@@ -161,7 +162,7 @@ fn Test() {
 // CHECK:STDOUT:     %ck.var_patt: %pattern_type.7ce = var_pattern %ck.patt [concrete]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %ck.var: ref %i32 = var %ck.var_patt
-// CHECK:STDOUT:   %c.ref.loc25: ref %Class = name_ref c, %c
+// CHECK:STDOUT:   %c.ref.loc25: %Class = name_ref c, %c
 // CHECK:STDOUT:   %k.ref.loc25: %Class.elem = name_ref k, @Class.%.loc16 [concrete = @Class.%.loc16]
 // CHECK:STDOUT:   %.loc25_18.1: ref %i32 = class_element_access %c.ref.loc25, element1
 // CHECK:STDOUT:   %.loc25_18.2: %i32 = bind_value %.loc25_18.1

+ 6 - 6
toolchain/check/testdata/class/generic/base_is_generic.carbon

@@ -666,9 +666,9 @@ fn H() {
 // CHECK:STDOUT:     %int_32.loc13_10: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
 // CHECK:STDOUT:     %i32.loc13_10: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc13_25.1: ref %i32 = temporary_storage
-// CHECK:STDOUT:   %.loc13_25.2: ref %i32 = temporary %.loc13_25.1, %G.call
-// CHECK:STDOUT:   %i: ref %i32 = bind_name i, %.loc13_25.2
+// CHECK:STDOUT:   %.loc13_25.1: %i32 = value_of_initializer %G.call
+// CHECK:STDOUT:   %.loc13_25.2: %i32 = converted %G.call, %.loc13_25.1
+// CHECK:STDOUT:   %i: %i32 = bind_name i, %.loc13_25.2
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -865,9 +865,9 @@ fn H() {
 // CHECK:STDOUT:     %int_32.loc7_10: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
 // CHECK:STDOUT:     %i32.loc7_10: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc7_25.1: ref %i32 = temporary_storage
-// CHECK:STDOUT:   %.loc7_25.2: ref %i32 = temporary %.loc7_25.1, %G.call
-// CHECK:STDOUT:   %j: ref %i32 = bind_name j, %.loc7_25.2
+// CHECK:STDOUT:   %.loc7_25.1: %i32 = value_of_initializer %G.call
+// CHECK:STDOUT:   %.loc7_25.2: %i32 = converted %G.call, %.loc7_25.1
+// CHECK:STDOUT:   %j: %i32 = bind_name j, %.loc7_25.2
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 9 - 11
toolchain/check/testdata/class/nested.carbon

@@ -227,13 +227,14 @@ fn F(a: Outer*) {
 // CHECK:STDOUT:   %a.ref.loc45: %ptr.5df = name_ref a, %a
 // CHECK:STDOUT:   %.loc45_26: ref %Outer = deref %a.ref.loc45
 // CHECK:STDOUT:   %pi.ref.loc45: %Outer.elem.fe9 = name_ref pi, @Outer.%.loc41 [concrete = @Outer.%.loc41]
-// CHECK:STDOUT:   %.loc45_29: ref %ptr.36a = class_element_access %.loc45_26, element2
+// CHECK:STDOUT:   %.loc45_29.1: ref %ptr.36a = class_element_access %.loc45_26, element2
 // CHECK:STDOUT:   %.loc45_21: type = splice_block %ptr.loc45 [concrete = constants.%ptr.36a] {
 // CHECK:STDOUT:     %Outer.ref.loc45: type = name_ref Outer, file.%Outer.decl [concrete = constants.%Outer]
 // CHECK:STDOUT:     %Inner.ref: type = name_ref Inner, @Outer.%Inner.decl [concrete = constants.%Inner]
 // CHECK:STDOUT:     %ptr.loc45: type = ptr_type %Inner.ref [concrete = constants.%ptr.36a]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %b: ref %ptr.36a = bind_name b, %.loc45_29
+// CHECK:STDOUT:   %.loc45_29.2: %ptr.36a = bind_value %.loc45_29.1
+// CHECK:STDOUT:   %b: %ptr.36a = bind_name b, %.loc45_29.2
 // CHECK:STDOUT:   %a.ref.loc47_3: %ptr.5df = name_ref a, %a
 // CHECK:STDOUT:   %.loc47_4.1: ref %Outer = deref %a.ref.loc47_3
 // CHECK:STDOUT:   %po.ref.loc47: %Outer.elem.a16 = name_ref po, @Outer.%.loc39 [concrete = @Outer.%.loc39]
@@ -256,16 +257,14 @@ fn F(a: Outer*) {
 // CHECK:STDOUT:   %.loc49_12.2: ref %ptr.36a = class_element_access %.loc49_12.1, element2
 // CHECK:STDOUT:   %.loc49_12.3: %ptr.36a = bind_value %.loc49_12.2
 // CHECK:STDOUT:   assign %.loc49_4.2, %.loc49_12.3
-// CHECK:STDOUT:   %b.ref.loc50: ref %ptr.36a = name_ref b, %b
-// CHECK:STDOUT:   %.loc50_3: %ptr.36a = bind_value %b.ref.loc50
-// CHECK:STDOUT:   %.loc50_4.1: ref %Inner = deref %.loc50_3
+// CHECK:STDOUT:   %b.ref.loc50: %ptr.36a = name_ref b, %b
+// CHECK:STDOUT:   %.loc50_4.1: ref %Inner = deref %b.ref.loc50
 // CHECK:STDOUT:   %po.ref.loc50: %Inner.elem.c30 = name_ref po, @Inner.%.loc23 [concrete = @Inner.%.loc23]
 // CHECK:STDOUT:   %.loc50_4.2: ref %ptr.5df = class_element_access %.loc50_4.1, element1
 // CHECK:STDOUT:   %a.ref.loc50: %ptr.5df = name_ref a, %a
 // CHECK:STDOUT:   assign %.loc50_4.2, %a.ref.loc50
-// CHECK:STDOUT:   %b.ref.loc51: ref %ptr.36a = name_ref b, %b
-// CHECK:STDOUT:   %.loc51_3: %ptr.36a = bind_value %b.ref.loc51
-// CHECK:STDOUT:   %.loc51_4.1: ref %Inner = deref %.loc51_3
+// CHECK:STDOUT:   %b.ref.loc51: %ptr.36a = name_ref b, %b
+// CHECK:STDOUT:   %.loc51_4.1: ref %Inner = deref %b.ref.loc51
 // CHECK:STDOUT:   %pi.ref.loc51_4: %Inner.elem.640 = name_ref pi, @Inner.%.loc22 [concrete = @Inner.%.loc22]
 // CHECK:STDOUT:   %.loc51_4.2: ref %ptr.36a = class_element_access %.loc51_4.1, element0
 // CHECK:STDOUT:   %a.ref.loc51: %ptr.5df = name_ref a, %a
@@ -274,9 +273,8 @@ fn F(a: Outer*) {
 // CHECK:STDOUT:   %.loc51_12.2: ref %ptr.36a = class_element_access %.loc51_12.1, element2
 // CHECK:STDOUT:   %.loc51_12.3: %ptr.36a = bind_value %.loc51_12.2
 // CHECK:STDOUT:   assign %.loc51_4.2, %.loc51_12.3
-// CHECK:STDOUT:   %b.ref.loc52: ref %ptr.36a = name_ref b, %b
-// CHECK:STDOUT:   %.loc52_3: %ptr.36a = bind_value %b.ref.loc52
-// CHECK:STDOUT:   %.loc52_4.1: ref %Inner = deref %.loc52_3
+// CHECK:STDOUT:   %b.ref.loc52: %ptr.36a = name_ref b, %b
+// CHECK:STDOUT:   %.loc52_4.1: ref %Inner = deref %b.ref.loc52
 // CHECK:STDOUT:   %qi.ref: %Inner.elem.640 = name_ref qi, @Inner.%.loc24 [concrete = @Inner.%.loc24]
 // CHECK:STDOUT:   %.loc52_4.2: ref %ptr.36a = class_element_access %.loc52_4.1, element2
 // CHECK:STDOUT:   %a.ref.loc52: %ptr.5df = name_ref a, %a

+ 3 - 2
toolchain/check/testdata/deduce/value_with_type_through_access.carbon

@@ -611,9 +611,10 @@ fn G() {
 // CHECK:STDOUT:   %.loc26_26.4: init type = initialize_from %C.ref to %.loc26_26.3 [concrete = constants.%C]
 // CHECK:STDOUT:   %.loc26_26.5: init %Class = class_init (%.loc26_26.4), %.loc26_26.2 [concrete = constants.%Class.val]
 // CHECK:STDOUT:   %.loc26_26.6: ref %Class = temporary %.loc26_26.2, %.loc26_26.5
-// CHECK:STDOUT:   %.loc26_28: ref %Class = converted %.loc26_26.1, %.loc26_26.6
+// CHECK:STDOUT:   %.loc26_28.1: ref %Class = converted %.loc26_26.1, %.loc26_26.6
 // CHECK:STDOUT:   %Class.ref.loc26_11: type = name_ref Class, file.%Class.decl [concrete = constants.%Class]
-// CHECK:STDOUT:   %c: %Class = bind_symbolic_name c, 0, %.loc26_28 [symbolic = constants.%c]
+// CHECK:STDOUT:   %.loc26_28.2: %Class = bind_value %.loc26_28.1
+// CHECK:STDOUT:   %c: %Class = bind_symbolic_name c, 0, %.loc26_28.2 [symbolic = constants.%c]
 // CHECK:STDOUT:   %F.ref: %F.type = name_ref F, file.%F.decl [concrete = constants.%F]
 // CHECK:STDOUT:   %.loc27_6.1: %empty_struct_type = struct_literal ()
 // CHECK:STDOUT:   %HoldsType.ref: %HoldsType.type = name_ref HoldsType, file.%HoldsType.decl [concrete = constants.%HoldsType.generic]

+ 5 - 4
toolchain/check/testdata/facet/convert_facet_value_as_type_knows_original_type.carbon

@@ -331,7 +331,7 @@ fn F() {
 // CHECK:STDOUT:   %.loc22_28.2: ref %Goat = temporary_storage
 // CHECK:STDOUT:   %.loc22_28.3: init %Goat = class_init (), %.loc22_28.2 [concrete = constants.%Goat.val]
 // CHECK:STDOUT:   %.loc22_28.4: ref %Goat = temporary %.loc22_28.2, %.loc22_28.3
-// CHECK:STDOUT:   %.loc22_30: ref %Goat = converted %.loc22_28.1, %.loc22_28.4
+// CHECK:STDOUT:   %.loc22_30.1: ref %Goat = converted %.loc22_28.1, %.loc22_28.4
 // CHECK:STDOUT:   %.loc22_15.1: type = splice_block %.loc22_15.3 [concrete = constants.%Goat] {
 // CHECK:STDOUT:     %Goat.ref.loc22_10: type = name_ref Goat, file.%Goat.decl [concrete = constants.%Goat]
 // CHECK:STDOUT:     %Animal.ref.loc22: type = name_ref Animal, file.%Animal.decl [concrete = constants.%Animal.type]
@@ -340,11 +340,12 @@ fn F() {
 // CHECK:STDOUT:     %as_type.loc22: type = facet_access_type %.loc22_15.2 [concrete = constants.%Goat]
 // CHECK:STDOUT:     %.loc22_15.3: type = converted %.loc22_15.2, %as_type.loc22 [concrete = constants.%Goat]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %x: ref %Goat = bind_name x, %.loc22_30
-// CHECK:STDOUT:   %x.ref.loc23: ref %Goat = name_ref x, %x
+// CHECK:STDOUT:   %.loc22_30.2: %Goat = bind_value %.loc22_30.1
+// CHECK:STDOUT:   %x: %Goat = bind_name x, %.loc22_30.2
+// CHECK:STDOUT:   %x.ref.loc23: %Goat = name_ref x, %x
 // CHECK:STDOUT:   %Bleet.ref.loc23: %Bleet.type = name_ref Bleet, @Goat.%Bleet.decl [concrete = constants.%Bleet]
 // CHECK:STDOUT:   %Bleet.call.loc23: init %empty_tuple.type = call %Bleet.ref.loc23()
-// CHECK:STDOUT:   %x.ref.loc24: ref %Goat = name_ref x, %x
+// CHECK:STDOUT:   %x.ref.loc24: %Goat = name_ref x, %x
 // CHECK:STDOUT:   %Eat.ref.loc24: %Eats.assoc_type = name_ref Eat, @Eats.%assoc0 [concrete = constants.%assoc0]
 // CHECK:STDOUT:   %impl.elem0.loc24: %.f6e = impl_witness_access constants.%Eats.impl_witness, element0 [concrete = constants.%Eat.73e]
 // CHECK:STDOUT:   %Eat.call.loc24: init %empty_tuple.type = call %impl.elem0.loc24()

+ 3 - 2
toolchain/check/testdata/facet/fail_deduction_uses_runtime_type_conversion.carbon

@@ -255,9 +255,10 @@ fn G(holds_to: HoldsType((RuntimeConvertTo, ))) {
 // CHECK:STDOUT:   %.loc30_36.2: ref %RuntimeConvertFrom = temporary_storage
 // CHECK:STDOUT:   %.loc30_36.3: init %RuntimeConvertFrom = class_init (), %.loc30_36.2 [concrete = constants.%RuntimeConvertFrom.val]
 // CHECK:STDOUT:   %.loc30_36.4: ref %RuntimeConvertFrom = temporary %.loc30_36.2, %.loc30_36.3
-// CHECK:STDOUT:   %.loc30_38: ref %RuntimeConvertFrom = converted %.loc30_36.1, %.loc30_36.4
+// CHECK:STDOUT:   %.loc30_38.1: ref %RuntimeConvertFrom = converted %.loc30_36.1, %.loc30_36.4
 // CHECK:STDOUT:   %RuntimeConvertFrom.ref.loc30_14: type = name_ref RuntimeConvertFrom, file.%RuntimeConvertFrom.decl [concrete = constants.%RuntimeConvertFrom]
-// CHECK:STDOUT:   %from: %RuntimeConvertFrom = bind_symbolic_name from, 0, %.loc30_38 [symbolic = constants.%from]
+// CHECK:STDOUT:   %.loc30_38.2: %RuntimeConvertFrom = bind_value %.loc30_38.1
+// CHECK:STDOUT:   %from: %RuntimeConvertFrom = bind_symbolic_name from, 0, %.loc30_38.2 [symbolic = constants.%from]
 // CHECK:STDOUT:   %F.ref: %F.type = name_ref F, file.%F.decl [concrete = constants.%F]
 // CHECK:STDOUT:   %from.ref: %RuntimeConvertFrom = name_ref from, %from [symbolic = constants.%from]
 // CHECK:STDOUT:   %holds_to.ref: %HoldsType.066 = name_ref holds_to, %holds_to

+ 3 - 2
toolchain/check/testdata/function/generic/type_param.carbon

@@ -77,9 +77,10 @@ fn F(T:! type) {
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:     %p.ref: ref @F.%ptr.loc16_11.2 (%ptr) = name_ref p, %p
 // CHECK:STDOUT:     %.loc17_15: @F.%ptr.loc16_11.2 (%ptr) = bind_value %p.ref
-// CHECK:STDOUT:     %.loc17_14: ref @F.%T.loc15_6.2 (%T) = deref %.loc17_15
+// CHECK:STDOUT:     %.loc17_14.1: ref @F.%T.loc15_6.2 (%T) = deref %.loc17_15
 // CHECK:STDOUT:     %T.ref.loc17: type = name_ref T, %T.loc15_6.1 [symbolic = %T.loc15_6.2 (constants.%T)]
-// CHECK:STDOUT:     %n: ref @F.%T.loc15_6.2 (%T) = bind_name n, %.loc17_14
+// CHECK:STDOUT:     %.loc17_14.2: @F.%T.loc15_6.2 (%T) = bind_value %.loc17_14.1
+// CHECK:STDOUT:     %n: @F.%T.loc15_6.2 (%T) = bind_name n, %.loc17_14.2
 // CHECK:STDOUT:     return
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }

+ 3 - 2
toolchain/check/testdata/impl/extend_impl_generic.carbon

@@ -270,12 +270,13 @@ class X(U:! type) {
 // CHECK:STDOUT:   %F.call.loc21: init %Param = call %impl.elem0.loc21() to %.loc21_20.1
 // CHECK:STDOUT:   %.loc21_20.2: ref %Param = temporary %.loc21_20.1, %F.call.loc21
 // CHECK:STDOUT:   %x.ref.loc21: %Param.elem = name_ref x, @Param.%.loc9 [concrete = @Param.%.loc9]
-// CHECK:STDOUT:   %.loc21_21: ref %i32 = class_element_access %.loc21_20.2, element0
+// CHECK:STDOUT:   %.loc21_21.1: ref %i32 = class_element_access %.loc21_20.2, element0
 // CHECK:STDOUT:   %.loc21_10: type = splice_block %i32.loc21 [concrete = constants.%i32] {
 // CHECK:STDOUT:     %int_32.loc21: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
 // CHECK:STDOUT:     %i32.loc21: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %a: ref %i32 = bind_name a, %.loc21_21
+// CHECK:STDOUT:   %.loc21_21.2: %i32 = bind_value %.loc21_21.1
+// CHECK:STDOUT:   %a: %i32 = bind_name a, %.loc21_21.2
 // CHECK:STDOUT:   name_binding_decl {
 // CHECK:STDOUT:     %b.patt: %pattern_type.7ce = binding_pattern b [concrete]
 // CHECK:STDOUT:     %b.var_patt: %pattern_type.7ce = var_pattern %b.patt [concrete]

+ 3 - 2
toolchain/check/testdata/impl/use_assoc_const.carbon

@@ -3871,7 +3871,7 @@ fn F() {
 // CHECK:STDOUT:   %.loc12_21.2: ref %C.131 = temporary_storage
 // CHECK:STDOUT:   %.loc12_21.3: init %C.131 = class_init (), %.loc12_21.2 [concrete = constants.%C.val]
 // CHECK:STDOUT:   %.loc12_21.4: ref %C.131 = temporary %.loc12_21.2, %.loc12_21.3
-// CHECK:STDOUT:   %.loc12_23: ref %C.131 = converted %.loc12_21.1, %.loc12_21.4
+// CHECK:STDOUT:   %.loc12_23.1: ref %C.131 = converted %.loc12_21.1, %.loc12_21.4
 // CHECK:STDOUT:   %.loc12_11.1: type = splice_block %impl.elem0 [concrete = constants.%C.131] {
 // CHECK:STDOUT:     %D.ref.loc12_10: type = name_ref D, file.%D.decl [concrete = constants.%D]
 // CHECK:STDOUT:     %Z.ref: type = name_ref Z, file.%Z.decl [concrete = constants.%Z.type]
@@ -3880,7 +3880,8 @@ fn F() {
 // CHECK:STDOUT:     %.loc12_11.2: %Z.type = converted %D.ref.loc12_10, %Z.facet [concrete = constants.%Z.facet.f2a]
 // CHECK:STDOUT:     %impl.elem0: type = impl_witness_access constants.%Z.impl_witness.19e, element0 [concrete = constants.%C.131]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %a: ref %C.131 = bind_name a, %.loc12_23
+// CHECK:STDOUT:   %.loc12_23.2: %C.131 = bind_value %.loc12_23.1
+// CHECK:STDOUT:   %a: %C.131 = bind_name a, %.loc12_23.2
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 3 - 3
toolchain/check/testdata/interop/cpp/function_return.carbon

@@ -135,9 +135,9 @@ fn F() {
 // CHECK:STDOUT:     %int_16: Core.IntLiteral = int_value 16 [concrete = constants.%int_16]
 // CHECK:STDOUT:     %i16: type = class_type @Int, @Int(constants.%int_16) [concrete = constants.%i16]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc7_30.1: ref %i16 = temporary_storage
-// CHECK:STDOUT:   %.loc7_30.2: ref %i16 = temporary %.loc7_30.1, %foo_short.call
-// CHECK:STDOUT:   %x: ref %i16 = bind_name x, %.loc7_30.2
+// CHECK:STDOUT:   %.loc7_30.1: %i16 = value_of_initializer %foo_short.call
+// CHECK:STDOUT:   %.loc7_30.2: %i16 = converted %foo_short.call, %.loc7_30.1
+// CHECK:STDOUT:   %x: %i16 = bind_name x, %.loc7_30.2
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 40 - 124
toolchain/check/testdata/let/convert.carbon

@@ -2,162 +2,78 @@
 // Exceptions. See /LICENSE for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
-// TODO: Add ranges and switch to "--dump-sem-ir-ranges=only".
-// EXTRA-ARGS: --dump-sem-ir-ranges=if-present
-//
 // AUTOUPDATE
 // TIP: To test this file alone, run:
 // TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/let/convert.carbon
 // TIP: To dump output, run:
 // TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/let/convert.carbon
 
+// --- convert.carbon
+
+library "[[@TEST_NAME]]";
+
 fn F() -> i32 {
   var v: (i32, i32, i32) = (1, 2, 3);
   // Convert from object representation to value representation.
+  //@dump-sem-ir-begin
   let w: (i32, i32, i32) = v;
+  //@dump-sem-ir-end
   return w.1;
 }
 
+// --- fail_let_bound_to_ref_not_mutable.carbon
+
+library "[[@TEST_NAME]]";
+
+fn G() {
+  var a: i32 = 0;
+  let n: i32 = a;
+  // CHECK:STDERR: fail_let_bound_to_ref_not_mutable.carbon:[[@LINE+4]]:3: error: expression is not assignable [AssignmentToNonAssignable]
+  // CHECK:STDERR:   n = 1;
+  // CHECK:STDERR:   ^
+  // CHECK:STDERR:
+  n = 1;
+}
+
 // CHECK:STDOUT: --- convert.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT:   %int_32: Core.IntLiteral = int_value 32 [concrete]
-// CHECK:STDOUT:   %Int.type: type = generic_class_type @Int [concrete]
-// CHECK:STDOUT:   %Int.generic: %Int.type = struct_value () [concrete]
 // CHECK:STDOUT:   %i32: type = class_type @Int, @Int(%int_32) [concrete]
-// CHECK:STDOUT:   %pattern_type.7ce: type = pattern_type %i32 [concrete]
-// CHECK:STDOUT:   %F.type: type = fn_type @F [concrete]
-// CHECK:STDOUT:   %F: %F.type = struct_value () [concrete]
 // CHECK:STDOUT:   %tuple.type.ff9: type = tuple_type (type, type, type) [concrete]
 // CHECK:STDOUT:   %tuple.type.189: type = tuple_type (%i32, %i32, %i32) [concrete]
 // CHECK:STDOUT:   %pattern_type.b5a: type = pattern_type %tuple.type.189 [concrete]
-// CHECK:STDOUT:   %int_1.5b8: Core.IntLiteral = int_value 1 [concrete]
-// CHECK:STDOUT:   %int_2.ecc: Core.IntLiteral = int_value 2 [concrete]
-// CHECK:STDOUT:   %int_3.1ba: Core.IntLiteral = int_value 3 [concrete]
-// CHECK:STDOUT:   %tuple.type.37f: type = tuple_type (Core.IntLiteral, Core.IntLiteral, Core.IntLiteral) [concrete]
-// CHECK:STDOUT:   %ImplicitAs.type.cc7: type = generic_interface_type @ImplicitAs [concrete]
-// CHECK:STDOUT:   %ImplicitAs.generic: %ImplicitAs.type.cc7 = struct_value () [concrete]
-// CHECK:STDOUT:   %ImplicitAs.type.205: type = facet_type <@ImplicitAs, @ImplicitAs(%i32)> [concrete]
-// CHECK:STDOUT:   %Convert.type.1b6: type = fn_type @Convert.1, @ImplicitAs(%i32) [concrete]
-// CHECK:STDOUT:   %To.c80: Core.IntLiteral = bind_symbolic_name To, 0 [symbolic]
-// CHECK:STDOUT:   %Convert.type.0f9: type = fn_type @Convert.3, @impl.4f9(%To.c80) [symbolic]
-// CHECK:STDOUT:   %Convert.f06: %Convert.type.0f9 = struct_value () [symbolic]
-// CHECK:STDOUT:   %ImplicitAs.impl_witness.c75: <witness> = impl_witness imports.%ImplicitAs.impl_witness_table.a2f, @impl.4f9(%int_32) [concrete]
-// CHECK:STDOUT:   %Convert.type.035: type = fn_type @Convert.3, @impl.4f9(%int_32) [concrete]
-// CHECK:STDOUT:   %Convert.956: %Convert.type.035 = struct_value () [concrete]
-// CHECK:STDOUT:   %ImplicitAs.facet.921: %ImplicitAs.type.205 = facet_value Core.IntLiteral, (%ImplicitAs.impl_witness.c75) [concrete]
-// CHECK:STDOUT:   %.9c3: type = fn_type_with_self_type %Convert.type.1b6, %ImplicitAs.facet.921 [concrete]
-// CHECK:STDOUT:   %Convert.bound.ab5: <bound method> = bound_method %int_1.5b8, %Convert.956 [concrete]
-// CHECK:STDOUT:   %Convert.specific_fn: <specific function> = specific_function %Convert.956, @Convert.3(%int_32) [concrete]
-// CHECK:STDOUT:   %bound_method.9a1: <bound method> = bound_method %int_1.5b8, %Convert.specific_fn [concrete]
-// CHECK:STDOUT:   %int_1.5d2: %i32 = int_value 1 [concrete]
-// CHECK:STDOUT:   %Convert.bound.ef9: <bound method> = bound_method %int_2.ecc, %Convert.956 [concrete]
-// CHECK:STDOUT:   %bound_method.b92: <bound method> = bound_method %int_2.ecc, %Convert.specific_fn [concrete]
-// CHECK:STDOUT:   %int_2.ef8: %i32 = int_value 2 [concrete]
-// CHECK:STDOUT:   %Convert.bound.b30: <bound method> = bound_method %int_3.1ba, %Convert.956 [concrete]
-// CHECK:STDOUT:   %bound_method.047: <bound method> = bound_method %int_3.1ba, %Convert.specific_fn [concrete]
-// CHECK:STDOUT:   %int_3.822: %i32 = int_value 3 [concrete]
-// CHECK:STDOUT:   %tuple: %tuple.type.189 = tuple_value (%int_1.5d2, %int_2.ef8, %int_3.822) [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [concrete] {
-// CHECK:STDOUT:     .Int = %Core.Int
-// CHECK:STDOUT:     .ImplicitAs = %Core.ImplicitAs
-// CHECK:STDOUT:     import Core//prelude
-// CHECK:STDOUT:     import Core//prelude/...
-// CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Core.Int: %Int.type = import_ref Core//prelude/types/int, Int, loaded [concrete = constants.%Int.generic]
-// CHECK:STDOUT:   %Core.ImplicitAs: %ImplicitAs.type.cc7 = import_ref Core//prelude/operators/as, ImplicitAs, loaded [concrete = constants.%ImplicitAs.generic]
-// CHECK:STDOUT:   %Core.import_ref.a5b: @impl.4f9.%Convert.type (%Convert.type.0f9) = import_ref Core//prelude/types/int, loc19_39, loaded [symbolic = @impl.4f9.%Convert (constants.%Convert.f06)]
-// CHECK:STDOUT:   %ImplicitAs.impl_witness_table.a2f = impl_witness_table (%Core.import_ref.a5b), @impl.4f9 [concrete]
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: file {
-// CHECK:STDOUT:   package: <namespace> = namespace [concrete] {
-// CHECK:STDOUT:     .Core = imports.%Core
-// CHECK:STDOUT:     .F = %F.decl
-// CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Core.import = import Core
-// CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {
-// CHECK:STDOUT:     %return.patt: %pattern_type.7ce = return_slot_pattern [concrete]
-// CHECK:STDOUT:     %return.param_patt: %pattern_type.7ce = out_param_pattern %return.patt, call_param0 [concrete]
-// CHECK:STDOUT:   } {
-// CHECK:STDOUT:     %int_32.loc14: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
-// CHECK:STDOUT:     %i32.loc14: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
-// CHECK:STDOUT:     %return.param: ref %i32 = out_param call_param0
-// CHECK:STDOUT:     %return: ref %i32 = return_slot %return.param
-// CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @F() -> %i32 {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   name_binding_decl {
-// CHECK:STDOUT:     %v.patt: %pattern_type.b5a = binding_pattern v [concrete]
-// CHECK:STDOUT:     %v.var_patt: %pattern_type.b5a = var_pattern %v.patt [concrete]
-// CHECK:STDOUT:   }
-// CHECK:STDOUT:   %v.var: ref %tuple.type.189 = var %v.var_patt
-// CHECK:STDOUT:   %int_1.loc15: Core.IntLiteral = int_value 1 [concrete = constants.%int_1.5b8]
-// CHECK:STDOUT:   %int_2: Core.IntLiteral = int_value 2 [concrete = constants.%int_2.ecc]
-// CHECK:STDOUT:   %int_3: Core.IntLiteral = int_value 3 [concrete = constants.%int_3.1ba]
-// CHECK:STDOUT:   %.loc15_36.1: %tuple.type.37f = tuple_literal (%int_1.loc15, %int_2, %int_3)
-// CHECK:STDOUT:   %impl.elem0.loc15_36.1: %.9c3 = impl_witness_access constants.%ImplicitAs.impl_witness.c75, element0 [concrete = constants.%Convert.956]
-// CHECK:STDOUT:   %bound_method.loc15_36.1: <bound method> = bound_method %int_1.loc15, %impl.elem0.loc15_36.1 [concrete = constants.%Convert.bound.ab5]
-// CHECK:STDOUT:   %specific_fn.loc15_36.1: <specific function> = specific_function %impl.elem0.loc15_36.1, @Convert.3(constants.%int_32) [concrete = constants.%Convert.specific_fn]
-// CHECK:STDOUT:   %bound_method.loc15_36.2: <bound method> = bound_method %int_1.loc15, %specific_fn.loc15_36.1 [concrete = constants.%bound_method.9a1]
-// CHECK:STDOUT:   %int.convert_checked.loc15_36.1: init %i32 = call %bound_method.loc15_36.2(%int_1.loc15) [concrete = constants.%int_1.5d2]
-// CHECK:STDOUT:   %.loc15_36.2: init %i32 = converted %int_1.loc15, %int.convert_checked.loc15_36.1 [concrete = constants.%int_1.5d2]
-// CHECK:STDOUT:   %tuple.elem0: ref %i32 = tuple_access %v.var, element0
-// CHECK:STDOUT:   %.loc15_36.3: init %i32 = initialize_from %.loc15_36.2 to %tuple.elem0 [concrete = constants.%int_1.5d2]
-// CHECK:STDOUT:   %impl.elem0.loc15_36.2: %.9c3 = impl_witness_access constants.%ImplicitAs.impl_witness.c75, element0 [concrete = constants.%Convert.956]
-// CHECK:STDOUT:   %bound_method.loc15_36.3: <bound method> = bound_method %int_2, %impl.elem0.loc15_36.2 [concrete = constants.%Convert.bound.ef9]
-// CHECK:STDOUT:   %specific_fn.loc15_36.2: <specific function> = specific_function %impl.elem0.loc15_36.2, @Convert.3(constants.%int_32) [concrete = constants.%Convert.specific_fn]
-// CHECK:STDOUT:   %bound_method.loc15_36.4: <bound method> = bound_method %int_2, %specific_fn.loc15_36.2 [concrete = constants.%bound_method.b92]
-// CHECK:STDOUT:   %int.convert_checked.loc15_36.2: init %i32 = call %bound_method.loc15_36.4(%int_2) [concrete = constants.%int_2.ef8]
-// CHECK:STDOUT:   %.loc15_36.4: init %i32 = converted %int_2, %int.convert_checked.loc15_36.2 [concrete = constants.%int_2.ef8]
-// CHECK:STDOUT:   %tuple.elem1.loc15: ref %i32 = tuple_access %v.var, element1
-// CHECK:STDOUT:   %.loc15_36.5: init %i32 = initialize_from %.loc15_36.4 to %tuple.elem1.loc15 [concrete = constants.%int_2.ef8]
-// CHECK:STDOUT:   %impl.elem0.loc15_36.3: %.9c3 = impl_witness_access constants.%ImplicitAs.impl_witness.c75, element0 [concrete = constants.%Convert.956]
-// CHECK:STDOUT:   %bound_method.loc15_36.5: <bound method> = bound_method %int_3, %impl.elem0.loc15_36.3 [concrete = constants.%Convert.bound.b30]
-// CHECK:STDOUT:   %specific_fn.loc15_36.3: <specific function> = specific_function %impl.elem0.loc15_36.3, @Convert.3(constants.%int_32) [concrete = constants.%Convert.specific_fn]
-// CHECK:STDOUT:   %bound_method.loc15_36.6: <bound method> = bound_method %int_3, %specific_fn.loc15_36.3 [concrete = constants.%bound_method.047]
-// CHECK:STDOUT:   %int.convert_checked.loc15_36.3: init %i32 = call %bound_method.loc15_36.6(%int_3) [concrete = constants.%int_3.822]
-// CHECK:STDOUT:   %.loc15_36.6: init %i32 = converted %int_3, %int.convert_checked.loc15_36.3 [concrete = constants.%int_3.822]
-// CHECK:STDOUT:   %tuple.elem2: ref %i32 = tuple_access %v.var, element2
-// CHECK:STDOUT:   %.loc15_36.7: init %i32 = initialize_from %.loc15_36.6 to %tuple.elem2 [concrete = constants.%int_3.822]
-// CHECK:STDOUT:   %.loc15_36.8: init %tuple.type.189 = tuple_init (%.loc15_36.3, %.loc15_36.5, %.loc15_36.7) to %v.var [concrete = constants.%tuple]
-// CHECK:STDOUT:   %.loc15_3: init %tuple.type.189 = converted %.loc15_36.1, %.loc15_36.8 [concrete = constants.%tuple]
-// CHECK:STDOUT:   assign %v.var, %.loc15_3
-// CHECK:STDOUT:   %.loc15_24.1: type = splice_block %.loc15_24.3 [concrete = constants.%tuple.type.189] {
-// CHECK:STDOUT:     %int_32.loc15_11: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
-// CHECK:STDOUT:     %i32.loc15_11: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
-// CHECK:STDOUT:     %int_32.loc15_16: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
-// CHECK:STDOUT:     %i32.loc15_16: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
-// CHECK:STDOUT:     %int_32.loc15_21: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
-// CHECK:STDOUT:     %i32.loc15_21: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
-// CHECK:STDOUT:     %.loc15_24.2: %tuple.type.ff9 = tuple_literal (%i32.loc15_11, %i32.loc15_16, %i32.loc15_21)
-// CHECK:STDOUT:     %.loc15_24.3: type = converted %.loc15_24.2, constants.%tuple.type.189 [concrete = constants.%tuple.type.189]
-// CHECK:STDOUT:   }
-// CHECK:STDOUT:   %v: ref %tuple.type.189 = bind_name v, %v.var
+// CHECK:STDOUT:   <elided>
 // CHECK:STDOUT:   name_binding_decl {
 // CHECK:STDOUT:     %w.patt: %pattern_type.b5a = binding_pattern w [concrete]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %v.ref: ref %tuple.type.189 = name_ref v, %v
-// CHECK:STDOUT:   %.loc17_24.1: type = splice_block %.loc17_24.3 [concrete = constants.%tuple.type.189] {
-// CHECK:STDOUT:     %int_32.loc17_11: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
-// CHECK:STDOUT:     %i32.loc17_11: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
-// CHECK:STDOUT:     %int_32.loc17_16: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
-// CHECK:STDOUT:     %i32.loc17_16: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
-// CHECK:STDOUT:     %int_32.loc17_21: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
-// CHECK:STDOUT:     %i32.loc17_21: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
-// CHECK:STDOUT:     %.loc17_24.2: %tuple.type.ff9 = tuple_literal (%i32.loc17_11, %i32.loc17_16, %i32.loc17_21)
-// CHECK:STDOUT:     %.loc17_24.3: type = converted %.loc17_24.2, constants.%tuple.type.189 [concrete = constants.%tuple.type.189]
+// CHECK:STDOUT:   %.loc8_24.1: type = splice_block %.loc8_24.3 [concrete = constants.%tuple.type.189] {
+// CHECK:STDOUT:     %int_32.loc8_11: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
+// CHECK:STDOUT:     %i32.loc8_11: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
+// CHECK:STDOUT:     %int_32.loc8_16: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
+// CHECK:STDOUT:     %i32.loc8_16: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
+// CHECK:STDOUT:     %int_32.loc8_21: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
+// CHECK:STDOUT:     %i32.loc8_21: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
+// CHECK:STDOUT:     %.loc8_24.2: %tuple.type.ff9 = tuple_literal (%i32.loc8_11, %i32.loc8_16, %i32.loc8_21)
+// CHECK:STDOUT:     %.loc8_24.3: type = converted %.loc8_24.2, constants.%tuple.type.189 [concrete = constants.%tuple.type.189]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %w: ref %tuple.type.189 = bind_name w, %v.ref
-// CHECK:STDOUT:   %w.ref: ref %tuple.type.189 = name_ref w, %w
-// CHECK:STDOUT:   %int_1.loc18: Core.IntLiteral = int_value 1 [concrete = constants.%int_1.5b8]
-// CHECK:STDOUT:   %tuple.elem1.loc18: ref %i32 = tuple_access %w.ref, element1
-// CHECK:STDOUT:   %.loc18: %i32 = bind_value %tuple.elem1.loc18
-// CHECK:STDOUT:   return %.loc18
+// CHECK:STDOUT:   %tuple.elem0.loc8: ref %i32 = tuple_access %v.ref, element0
+// CHECK:STDOUT:   %.loc8_28.1: %i32 = bind_value %tuple.elem0.loc8
+// CHECK:STDOUT:   %tuple.elem1.loc8: ref %i32 = tuple_access %v.ref, element1
+// CHECK:STDOUT:   %.loc8_28.2: %i32 = bind_value %tuple.elem1.loc8
+// CHECK:STDOUT:   %tuple.elem2.loc8: ref %i32 = tuple_access %v.ref, element2
+// CHECK:STDOUT:   %.loc8_28.3: %i32 = bind_value %tuple.elem2.loc8
+// CHECK:STDOUT:   %tuple: %tuple.type.189 = tuple_value (%.loc8_28.1, %.loc8_28.2, %.loc8_28.3)
+// CHECK:STDOUT:   %.loc8_28.4: %tuple.type.189 = converted %v.ref, %tuple
+// CHECK:STDOUT:   %w: %tuple.type.189 = bind_name w, %.loc8_28.4
+// CHECK:STDOUT:   <elided>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 24 - 21
toolchain/check/testdata/operators/overloaded/index_with_prelude.carbon

@@ -146,7 +146,8 @@ let x: i32 = c[0];
 // CHECK:STDOUT:   %.loc14_25.2: init %SubscriptType.8ee = class_init (), %.loc14_25.1 [concrete = constants.%SubscriptType.val]
 // CHECK:STDOUT:   %.loc14_25.3: ref %SubscriptType.8ee = temporary %.loc14_25.1, %.loc14_25.2
 // CHECK:STDOUT:   %.loc14_25.4: ref %SubscriptType.8ee = converted @__global_init.%.loc14, %.loc14_25.3
-// CHECK:STDOUT:   %s: ref %SubscriptType.8ee = bind_name s, %.loc14_25.4
+// CHECK:STDOUT:   %.loc14_25.5: %SubscriptType.8ee = bind_value %.loc14_25.4
+// CHECK:STDOUT:   %s: %SubscriptType.8ee = bind_name s, %.loc14_25.5
 // CHECK:STDOUT:   name_binding_decl {
 // CHECK:STDOUT:     %c.patt: %pattern_type.c48 = binding_pattern c [concrete]
 // CHECK:STDOUT:   }
@@ -155,13 +156,15 @@ let x: i32 = c[0];
 // CHECK:STDOUT:   %.loc15_13.2: init %C = class_init (), %.loc15_13.1 [concrete = constants.%C.val]
 // CHECK:STDOUT:   %.loc15_13.3: ref %C = temporary %.loc15_13.1, %.loc15_13.2
 // CHECK:STDOUT:   %.loc15_13.4: ref %C = converted @__global_init.%.loc15, %.loc15_13.3
-// CHECK:STDOUT:   %c: ref %C = bind_name c, %.loc15_13.4
+// CHECK:STDOUT:   %.loc15_13.5: %C = bind_value %.loc15_13.4
+// CHECK:STDOUT:   %c: %C = bind_name c, %.loc15_13.5
 // CHECK:STDOUT:   name_binding_decl {
 // CHECK:STDOUT:     %x.patt: %pattern_type.c39 = binding_pattern x [concrete]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %ElementType.ref: type = name_ref ElementType, %ElementType.decl [concrete = constants.%ElementType.e6b]
-// CHECK:STDOUT:   %.loc16: ref %ElementType.e6b = temporary @__global_init.%.loc16_25, @__global_init.%At.call
-// CHECK:STDOUT:   %x: ref %ElementType.e6b = bind_name x, %.loc16
+// CHECK:STDOUT:   %.loc16_25.1: ref %ElementType.e6b = temporary @__global_init.%.loc16, @__global_init.%At.call
+// CHECK:STDOUT:   %.loc16_25.2: %ElementType.e6b = bind_value %.loc16_25.1
+// CHECK:STDOUT:   %x: %ElementType.e6b = bind_name x, %.loc16_25.2
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: impl @impl: %C.ref as %IndexWith.type {
@@ -230,14 +233,12 @@ let x: i32 = c[0];
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %.loc14: %empty_struct_type = struct_literal ()
 // CHECK:STDOUT:   %.loc15: %empty_struct_type = struct_literal ()
-// CHECK:STDOUT:   %c.ref: ref %C = name_ref c, file.%c
-// CHECK:STDOUT:   %s.ref: ref %SubscriptType.8ee = name_ref s, file.%s
-// CHECK:STDOUT:   %.loc16_24: %SubscriptType.8ee = bind_value %s.ref
+// CHECK:STDOUT:   %c.ref: %C = name_ref c, file.%c
+// CHECK:STDOUT:   %s.ref: %SubscriptType.8ee = name_ref s, file.%s
 // CHECK:STDOUT:   %impl.elem0: %.d94 = impl_witness_access constants.%IndexWith.impl_witness, element0 [concrete = constants.%At.d43]
 // CHECK:STDOUT:   %bound_method: <bound method> = bound_method %c.ref, %impl.elem0
-// CHECK:STDOUT:   %.loc16_25: ref %ElementType.e6b = temporary_storage
-// CHECK:STDOUT:   %.loc16_22: %C = bind_value %c.ref
-// CHECK:STDOUT:   %At.call: init %ElementType.e6b = call %bound_method(%.loc16_22, %.loc16_24) to %.loc16_25
+// CHECK:STDOUT:   %.loc16: ref %ElementType.e6b = temporary_storage
+// CHECK:STDOUT:   %At.call: init %ElementType.e6b = call %bound_method(%c.ref, %s.ref) to %.loc16
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -364,9 +365,9 @@ let x: i32 = c[0];
 // CHECK:STDOUT:     %int_32.loc11: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
 // CHECK:STDOUT:     %i32.loc11: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc11_17.1: ref %i32 = temporary_storage
-// CHECK:STDOUT:   %.loc11_17.2: ref %i32 = temporary %.loc11_17.1, @__global_init.%At.call
-// CHECK:STDOUT:   %e: ref %i32 = bind_name e, %.loc11_17.2
+// CHECK:STDOUT:   %.loc11_17.1: %i32 = value_of_initializer @__global_init.%At.call
+// CHECK:STDOUT:   %.loc11_17.2: %i32 = converted @__global_init.%At.call, %.loc11_17.1
+// CHECK:STDOUT:   %e: %i32 = bind_name e, %.loc11_17.2
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: impl @impl.18b: %.loc4_15.2 as %IndexWith.type {
@@ -495,13 +496,15 @@ let x: i32 = c[0];
 // CHECK:STDOUT:   %.loc14_13.2: init %C = class_init (), %.loc14_13.1 [concrete = constants.%C.val]
 // CHECK:STDOUT:   %.loc14_13.3: ref %C = temporary %.loc14_13.1, %.loc14_13.2
 // CHECK:STDOUT:   %.loc14_13.4: ref %C = converted @__global_init.%.loc14, %.loc14_13.3
-// CHECK:STDOUT:   %c: ref %C = bind_name c, %.loc14_13.4
+// CHECK:STDOUT:   %.loc14_13.5: %C = bind_value %.loc14_13.4
+// CHECK:STDOUT:   %c: %C = bind_name c, %.loc14_13.5
 // CHECK:STDOUT:   name_binding_decl {
 // CHECK:STDOUT:     %x.patt: %pattern_type.c39 = binding_pattern x [concrete]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %ElementType.ref: type = name_ref ElementType, %ElementType.decl [concrete = constants.%ElementType.e6b]
-// CHECK:STDOUT:   %.loc22: ref %ElementType.e6b = temporary @__global_init.%.loc22_25.2, @__global_init.%At.call
-// CHECK:STDOUT:   %x: ref %ElementType.e6b = bind_name x, %.loc22
+// CHECK:STDOUT:   %.loc22_25.1: ref %ElementType.e6b = temporary @__global_init.%.loc22_25.2, @__global_init.%At.call
+// CHECK:STDOUT:   %.loc22_25.2: %ElementType.e6b = bind_value %.loc22_25.1
+// CHECK:STDOUT:   %x: %ElementType.e6b = bind_name x, %.loc22_25.2
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: impl @impl.066: %C.ref as %IndexWith.type {
@@ -569,14 +572,13 @@ let x: i32 = c[0];
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %.loc14: %empty_struct_type = struct_literal ()
-// CHECK:STDOUT:   %c.ref: ref %C = name_ref c, file.%c
+// CHECK:STDOUT:   %c.ref: %C = name_ref c, file.%c
 // CHECK:STDOUT:   %int_0: Core.IntLiteral = int_value 0 [concrete = constants.%int_0]
 // CHECK:STDOUT:   %.loc22_25.1: %SubscriptType.8ee = converted %int_0, <error> [concrete = <error>]
 // CHECK:STDOUT:   %impl.elem0: %.d94 = impl_witness_access constants.%IndexWith.impl_witness, element0 [concrete = constants.%At.d43]
 // CHECK:STDOUT:   %bound_method: <bound method> = bound_method %c.ref, %impl.elem0
 // CHECK:STDOUT:   %.loc22_25.2: ref %ElementType.e6b = temporary_storage
-// CHECK:STDOUT:   %.loc22_22: %C = bind_value %c.ref
-// CHECK:STDOUT:   %At.call: init %ElementType.e6b = call %bound_method(%.loc22_22, <error>) to %.loc22_25.2
+// CHECK:STDOUT:   %At.call: init %ElementType.e6b = call %bound_method(%c.ref, <error>) to %.loc22_25.2
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -626,7 +628,8 @@ let x: i32 = c[0];
 // CHECK:STDOUT:   %.loc6_13.2: init %C = class_init (), %.loc6_13.1 [concrete = constants.%C.val]
 // CHECK:STDOUT:   %.loc6_13.3: ref %C = temporary %.loc6_13.1, %.loc6_13.2
 // CHECK:STDOUT:   %.loc6_13.4: ref %C = converted @__global_init.%.loc6, %.loc6_13.3
-// CHECK:STDOUT:   %c: ref %C = bind_name c, %.loc6_13.4
+// CHECK:STDOUT:   %.loc6_13.5: %C = bind_value %.loc6_13.4
+// CHECK:STDOUT:   %c: %C = bind_name c, %.loc6_13.5
 // CHECK:STDOUT:   name_binding_decl {
 // CHECK:STDOUT:     %x.patt: %pattern_type.7ce = binding_pattern x [concrete]
 // CHECK:STDOUT:   }
@@ -649,7 +652,7 @@ let x: i32 = c[0];
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %.loc6: %empty_struct_type = struct_literal ()
-// CHECK:STDOUT:   %c.ref: ref %C = name_ref c, file.%c
+// CHECK:STDOUT:   %c.ref: %C = name_ref c, file.%c
 // CHECK:STDOUT:   %int_0: Core.IntLiteral = int_value 0 [concrete = constants.%int_0]
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }

+ 7 - 2
toolchain/check/testdata/var/var_pattern.carbon

@@ -753,6 +753,7 @@ fn G() {
 // CHECK:STDOUT:   %G: %G.type = struct_value () [concrete]
 // CHECK:STDOUT:   %tuple.type: type = tuple_type (%empty_tuple.type, %empty_tuple.type, %empty_tuple.type) [concrete]
 // CHECK:STDOUT:   %pattern_type.8c1: type = pattern_type %tuple.type [concrete]
+// CHECK:STDOUT:   %empty_tuple: %empty_tuple.type = tuple_value () [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -805,7 +806,9 @@ fn G() {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc8_38.1: ref %empty_tuple.type = temporary_storage
 // CHECK:STDOUT:   %.loc8_38.2: ref %empty_tuple.type = temporary %.loc8_38.1, %F.call.loc8_38
-// CHECK:STDOUT:   %x: ref %empty_tuple.type = bind_name x, %.loc8_38.2
+// CHECK:STDOUT:   %tuple.loc8_38: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple]
+// CHECK:STDOUT:   %.loc8_38.3: %empty_tuple.type = converted %F.call.loc8_38, %tuple.loc8_38 [concrete = constants.%empty_tuple]
+// CHECK:STDOUT:   %x: %empty_tuple.type = bind_name x, %.loc8_38.3
 // CHECK:STDOUT:   assign %y.var, %F.call.loc8_43
 // CHECK:STDOUT:   %.loc8_23.1: type = splice_block %.loc8_23.3 [concrete = constants.%empty_tuple.type] {
 // CHECK:STDOUT:     %.loc8_23.2: %empty_tuple.type = tuple_literal ()
@@ -818,7 +821,9 @@ fn G() {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc8_48.1: ref %empty_tuple.type = temporary_storage
 // CHECK:STDOUT:   %.loc8_48.2: ref %empty_tuple.type = temporary %.loc8_48.1, %F.call.loc8_48
-// CHECK:STDOUT:   %z: ref %empty_tuple.type = bind_name z, %.loc8_48.2
+// CHECK:STDOUT:   %tuple.loc8_48: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple]
+// CHECK:STDOUT:   %.loc8_48.3: %empty_tuple.type = converted %F.call.loc8_48, %tuple.loc8_48 [concrete = constants.%empty_tuple]
+// CHECK:STDOUT:   %z: %empty_tuple.type = bind_name z, %.loc8_48.3
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 7 - 0
toolchain/diagnostics/coverage_test.cpp

@@ -51,6 +51,13 @@ constexpr Kind UntestedKinds[] = {
     // - Require all diagnostics produced by compiling have their first location
     //   be in the file being compiled, never an import.
     Kind::LanguageServerDiagnosticInWrongFile,
+
+    // TODO: This can only fire if we attempt to convert a non-reference
+    // expression to a durable reference binding. At the moment, the only time
+    // we attempt reference binding is within a `var` pattern, where the
+    // conversion cannot fail. This should be covered once we support `ref`
+    // binding syntax.
+    Kind::ConversionFailureNonRefToRef,
 };
 
 // Looks for diagnostic kinds that aren't covered by a file_test.

+ 1 - 0
toolchain/diagnostics/diagnostic_kind.def

@@ -440,6 +440,7 @@ CARBON_DIAGNOSTIC_KIND(ConversionFailure)
 CARBON_DIAGNOSTIC_KIND(ConversionFailureNonTypeToFacet)
 CARBON_DIAGNOSTIC_KIND(ConversionFailureFacetToFacet)
 CARBON_DIAGNOSTIC_KIND(ConversionFailureTypeToFacet)
+CARBON_DIAGNOSTIC_KIND(ConversionFailureNonRefToRef)
 CARBON_DIAGNOSTIC_KIND(TypeExprEvaluationFailure)
 CARBON_DIAGNOSTIC_KIND(UnexpectedDeclNameParams)
 CARBON_DIAGNOSTIC_KIND(QualifiedNameInNonScope)

+ 4 - 8
toolchain/lower/testdata/class/method.carbon

@@ -30,11 +30,8 @@ fn F(p: C*) {
 // CHECK:STDOUT: define void @_CF.Main(ptr %p) !dbg !4 {
 // CHECK:STDOUT: entry:
 // CHECK:STDOUT:   %Get.call = call i32 @_CGet.C.Main(ptr %p), !dbg !7
-// CHECK:STDOUT:   %.loc19_25.1.temp = alloca i32, align 4, !dbg !7
-// CHECK:STDOUT:   store i32 %Get.call, ptr %.loc19_25.1.temp, align 4, !dbg !7
-// CHECK:STDOUT:   %.loc20_12 = load i32, ptr %.loc19_25.1.temp, align 4, !dbg !8
-// CHECK:STDOUT:   call void @_CSet.C.Main(ptr %p, i32 %.loc20_12), !dbg !9
-// CHECK:STDOUT:   ret void, !dbg !10
+// CHECK:STDOUT:   call void @_CSet.C.Main(ptr %p, i32 %Get.call), !dbg !8
+// CHECK:STDOUT:   ret void, !dbg !9
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !llvm.module.flags = !{!0, !1}
@@ -48,6 +45,5 @@ fn F(p: C*) {
 // CHECK:STDOUT: !5 = !DISubroutineType(types: !6)
 // CHECK:STDOUT: !6 = !{}
 // CHECK:STDOUT: !7 = !DILocation(line: 19, column: 16, scope: !4)
-// CHECK:STDOUT: !8 = !DILocation(line: 20, column: 12, scope: !4)
-// CHECK:STDOUT: !9 = !DILocation(line: 20, column: 3, scope: !4)
-// CHECK:STDOUT: !10 = !DILocation(line: 18, column: 1, scope: !4)
+// CHECK:STDOUT: !8 = !DILocation(line: 20, column: 3, scope: !4)
+// CHECK:STDOUT: !9 = !DILocation(line: 18, column: 1, scope: !4)

+ 0 - 4
toolchain/lower/testdata/function/generic/call_different_impls_with_const.carbon

@@ -69,16 +69,12 @@ fn Run() {
 // CHECK:STDOUT: define linkonce_odr void @_CG.Main.ae78220c5e9d4af5() !dbg !16 {
 // CHECK:STDOUT: entry:
 // CHECK:STDOUT:   %.loc35_20.1 = call i1 @"_CF.X.Main:I.Main"(), !dbg !17
-// CHECK:STDOUT:   %.loc35_20.2.temp = alloca i1, align 1, !dbg !17
-// CHECK:STDOUT:   store i1 %.loc35_20.1, ptr %.loc35_20.2.temp, align 1, !dbg !17
 // CHECK:STDOUT:   ret void, !dbg !18
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: define linkonce_odr void @_CG.Main.6b293b16be321a45() !dbg !19 {
 // CHECK:STDOUT: entry:
 // CHECK:STDOUT:   %.loc35_20.1 = call i32 @"_CF.Y.Main:I.Main"(), !dbg !20
-// CHECK:STDOUT:   %.loc35_20.2.temp = alloca i32, align 4, !dbg !20
-// CHECK:STDOUT:   store i32 %.loc35_20.1, ptr %.loc35_20.2.temp, align 4, !dbg !20
 // CHECK:STDOUT:   ret void, !dbg !21
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 64 - 0
toolchain/lower/testdata/let/copy_value_rep.carbon

@@ -0,0 +1,64 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// AUTOUPDATE
+// TIP: To test this file alone, run:
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lower/testdata/let/copy_value_rep.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/let/copy_value_rep.carbon
+
+class X {
+  var a: i32;
+}
+
+fn Run() -> i32 {
+  var x: X = {.a = 1};
+  let n: i32 = x.a;
+  x.a = 2;
+  // Should return 1, not 2.
+  return n;
+}
+
+// CHECK:STDOUT: ; ModuleID = 'copy_value_rep.carbon'
+// CHECK:STDOUT: source_filename = "copy_value_rep.carbon"
+// CHECK:STDOUT:
+// CHECK:STDOUT: @X.val.loc16_3 = internal constant { i32 } { i32 1 }
+// CHECK:STDOUT:
+// CHECK:STDOUT: define i32 @main() !dbg !4 {
+// CHECK:STDOUT: entry:
+// CHECK:STDOUT:   %x.var = alloca { i32 }, align 8, !dbg !7
+// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(i64 4, ptr %x.var), !dbg !7
+// CHECK:STDOUT:   %.loc16_21.3.a = getelementptr inbounds nuw { i32 }, ptr %x.var, i32 0, i32 0, !dbg !8
+// CHECK:STDOUT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x.var, ptr align 4 @X.val.loc16_3, i64 4, i1 false), !dbg !7
+// CHECK:STDOUT:   %.loc17_17.1.a = getelementptr inbounds nuw { i32 }, ptr %x.var, i32 0, i32 0, !dbg !9
+// CHECK:STDOUT:   %.loc17_17.2 = load i32, ptr %.loc17_17.1.a, align 4, !dbg !9
+// CHECK:STDOUT:   %.loc18_4.a = getelementptr inbounds nuw { i32 }, ptr %x.var, i32 0, i32 0, !dbg !10
+// CHECK:STDOUT:   store i32 2, ptr %.loc18_4.a, align 4, !dbg !10
+// CHECK:STDOUT:   ret i32 %.loc17_17.2, !dbg !11
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
+// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(i64 immarg, ptr captures(none)) #0
+// CHECK:STDOUT:
+// CHECK:STDOUT: ; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
+// CHECK:STDOUT: declare void @llvm.memcpy.p0.p0.i64(ptr noalias writeonly captures(none), ptr noalias readonly captures(none), i64, i1 immarg) #1
+// CHECK:STDOUT:
+// CHECK:STDOUT: attributes #0 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
+// CHECK:STDOUT: attributes #1 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
+// CHECK:STDOUT:
+// CHECK:STDOUT: !llvm.module.flags = !{!0, !1}
+// CHECK:STDOUT: !llvm.dbg.cu = !{!2}
+// CHECK:STDOUT:
+// CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5}
+// CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3}
+// CHECK:STDOUT: !2 = distinct !DICompileUnit(language: DW_LANG_C, file: !3, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
+// CHECK:STDOUT: !3 = !DIFile(filename: "copy_value_rep.carbon", directory: "")
+// CHECK:STDOUT: !4 = distinct !DISubprogram(name: "Run", linkageName: "main", scope: null, file: !3, line: 15, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !5 = !DISubroutineType(types: !6)
+// CHECK:STDOUT: !6 = !{}
+// CHECK:STDOUT: !7 = !DILocation(line: 16, column: 3, scope: !4)
+// CHECK:STDOUT: !8 = !DILocation(line: 16, column: 14, scope: !4)
+// CHECK:STDOUT: !9 = !DILocation(line: 17, column: 16, scope: !4)
+// CHECK:STDOUT: !10 = !DILocation(line: 18, column: 3, scope: !4)
+// CHECK:STDOUT: !11 = !DILocation(line: 20, column: 3, scope: !4)