浏览代码

Track the instruction used to name the type and constraint in an impl. (#4368)

This is necessary in order to have access to the specific versions of
their constant values in a generic impl.

Stub out impl deduction.
Richard Smith 1 年之前
父节点
当前提交
568ad197d1
共有 79 个文件被更改,包括 590 次插入341 次删除
  1. 15 0
      toolchain/check/deduce.cpp
  2. 6 0
      toolchain/check/deduce.h
  3. 27 14
      toolchain/check/handle_impl.cpp
  4. 5 3
      toolchain/check/impl.cpp
  5. 48 21
      toolchain/check/import_ref.cpp
  6. 22 7
      toolchain/check/member_access.cpp
  7. 1 1
      toolchain/check/node_stack.h
  8. 4 4
      toolchain/check/testdata/as/overloaded.carbon
  9. 2 2
      toolchain/check/testdata/function/builtin/method.carbon
  10. 3 3
      toolchain/check/testdata/function/builtin/no_prelude/call_from_operator.carbon
  11. 5 5
      toolchain/check/testdata/impl/compound.carbon
  12. 1 1
      toolchain/check/testdata/impl/declaration.carbon
  13. 1 1
      toolchain/check/testdata/impl/empty.carbon
  14. 4 3
      toolchain/check/testdata/impl/extend_impl.carbon
  15. 2 2
      toolchain/check/testdata/impl/fail_call_invalid.carbon
  16. 2 1
      toolchain/check/testdata/impl/fail_extend_impl_forall.carbon
  17. 1 1
      toolchain/check/testdata/impl/fail_extend_impl_scope.carbon
  18. 3 3
      toolchain/check/testdata/impl/fail_extend_impl_type_as.carbon
  19. 2 1
      toolchain/check/testdata/impl/fail_extend_non_interface.carbon
  20. 10 2
      toolchain/check/testdata/impl/fail_extend_partially_defined_interface.carbon
  21. 2 1
      toolchain/check/testdata/impl/fail_extend_undefined_interface.carbon
  22. 2 1
      toolchain/check/testdata/impl/fail_impl_as_scope.carbon
  23. 1 1
      toolchain/check/testdata/impl/fail_impl_bad_assoc_const.carbon
  24. 30 15
      toolchain/check/testdata/impl/fail_impl_bad_assoc_fn.carbon
  25. 1 1
      toolchain/check/testdata/impl/fail_impl_bad_interface.carbon
  26. 1 1
      toolchain/check/testdata/impl/fail_redefinition.carbon
  27. 1 1
      toolchain/check/testdata/impl/fail_todo_impl_assoc_const.carbon
  28. 2 1
      toolchain/check/testdata/impl/impl_as.carbon
  29. 1 1
      toolchain/check/testdata/impl/impl_forall.carbon
  30. 3 3
      toolchain/check/testdata/impl/lookup/alias.carbon
  31. 3 2
      toolchain/check/testdata/impl/lookup/fail_todo_undefined_impl.carbon
  32. 15 13
      toolchain/check/testdata/impl/lookup/import.carbon
  33. 3 2
      toolchain/check/testdata/impl/lookup/instance_method.carbon
  34. 1 1
      toolchain/check/testdata/impl/lookup/no_prelude/impl_forall.carbon
  35. 15 13
      toolchain/check/testdata/impl/lookup/no_prelude/import.carbon
  36. 1 1
      toolchain/check/testdata/impl/no_prelude/basic.carbon
  37. 81 0
      toolchain/check/testdata/impl/no_prelude/fail_alias.carbon
  38. 1 1
      toolchain/check/testdata/impl/no_prelude/fail_impl_bad_type.carbon
  39. 11 11
      toolchain/check/testdata/impl/no_prelude/generic_redeclaration.carbon
  40. 18 18
      toolchain/check/testdata/impl/no_prelude/import_generic.carbon
  41. 2 2
      toolchain/check/testdata/impl/no_prelude/import_self.carbon
  42. 61 53
      toolchain/check/testdata/impl/no_prelude/interface_args.carbon
  43. 16 8
      toolchain/check/testdata/impl/no_prelude/no_definition_in_impl_file.carbon
  44. 1 1
      toolchain/check/testdata/impl/no_prelude/self_in_class.carbon
  45. 4 4
      toolchain/check/testdata/impl/no_prelude/self_in_signature.carbon
  46. 2 2
      toolchain/check/testdata/impl/redeclaration.carbon
  47. 2 2
      toolchain/check/testdata/interface/no_prelude/default_fn.carbon
  48. 4 2
      toolchain/check/testdata/interface/no_prelude/generic.carbon
  49. 1 1
      toolchain/check/testdata/interface/no_prelude/generic_import.carbon
  50. 5 5
      toolchain/check/testdata/interface/no_prelude/generic_vs_params.carbon
  51. 6 4
      toolchain/check/testdata/interface/no_prelude/import_interface_decl.carbon
  52. 4 4
      toolchain/check/testdata/operators/overloaded/add.carbon
  53. 4 4
      toolchain/check/testdata/operators/overloaded/bit_and.carbon
  54. 2 2
      toolchain/check/testdata/operators/overloaded/bit_complement.carbon
  55. 4 4
      toolchain/check/testdata/operators/overloaded/bit_or.carbon
  56. 4 4
      toolchain/check/testdata/operators/overloaded/bit_xor.carbon
  57. 2 2
      toolchain/check/testdata/operators/overloaded/dec.carbon
  58. 4 4
      toolchain/check/testdata/operators/overloaded/div.carbon
  59. 5 5
      toolchain/check/testdata/operators/overloaded/eq.carbon
  60. 4 4
      toolchain/check/testdata/operators/overloaded/fail_assign_non_ref.carbon
  61. 4 4
      toolchain/check/testdata/operators/overloaded/fail_no_impl_for_arg.carbon
  62. 4 4
      toolchain/check/testdata/operators/overloaded/implicit_as.carbon
  63. 2 2
      toolchain/check/testdata/operators/overloaded/inc.carbon
  64. 4 4
      toolchain/check/testdata/operators/overloaded/left_shift.carbon
  65. 4 4
      toolchain/check/testdata/operators/overloaded/mod.carbon
  66. 4 4
      toolchain/check/testdata/operators/overloaded/mul.carbon
  67. 2 2
      toolchain/check/testdata/operators/overloaded/negate.carbon
  68. 5 5
      toolchain/check/testdata/operators/overloaded/ordered.carbon
  69. 4 4
      toolchain/check/testdata/operators/overloaded/right_shift.carbon
  70. 4 4
      toolchain/check/testdata/operators/overloaded/sub.carbon
  71. 1 1
      toolchain/check/testdata/where_expr/constraints.carbon
  72. 4 3
      toolchain/lower/mangler.cpp
  73. 8 1
      toolchain/lower/mangler.h
  74. 1 0
      toolchain/sem_ir/BUILD
  75. 1 2
      toolchain/sem_ir/constant.h
  76. 11 1
      toolchain/sem_ir/file.cpp
  77. 4 4
      toolchain/sem_ir/formatter.cpp
  78. 22 0
      toolchain/sem_ir/impl.cpp
  79. 7 12
      toolchain/sem_ir/impl.h

+ 15 - 0
toolchain/check/deduce.cpp

@@ -10,6 +10,7 @@
 #include "toolchain/check/generic.h"
 #include "toolchain/check/subst.h"
 #include "toolchain/sem_ir/ids.h"
+#include "toolchain/sem_ir/impl.h"
 #include "toolchain/sem_ir/typed_insts.h"
 
 namespace Carbon::Check {
@@ -238,4 +239,18 @@ auto DeduceGenericCallArguments(
                       context.inst_blocks().AddCanonical(result_arg_ids));
 }
 
+// Deduces the impl arguments to use in a use of a parameterized impl. Returns
+// `Invalid` if deduction fails.
+auto DeduceImplArguments(Context& context, const SemIR::Impl& impl,
+                         SemIR::ConstantId self_id,
+                         SemIR::ConstantId constraint_id) -> SemIR::SpecificId {
+  CARBON_CHECK(impl.generic_id.is_valid(),
+               "Performing deduction for non-generic impl");
+  // TODO: This is a placeholder. Implement deduction.
+  static_cast<void>(context);
+  static_cast<void>(self_id);
+  static_cast<void>(constraint_id);
+  return SemIR::SpecificId::Invalid;
+}
+
 }  // namespace Carbon::Check

+ 6 - 0
toolchain/check/deduce.h

@@ -20,6 +20,12 @@ auto DeduceGenericCallArguments(Context& context, SemIR::LocId loc_id,
                                 llvm::ArrayRef<SemIR::InstId> arg_ids)
     -> SemIR::SpecificId;
 
+// Deduces the impl arguments to use in a use of a parameterized impl. Returns
+// `Invalid` if deduction fails.
+auto DeduceImplArguments(Context& context, const SemIR::Impl& impl,
+                         SemIR::ConstantId self_id,
+                         SemIR::ConstantId constraint_id) -> SemIR::SpecificId;
+
 }  // namespace Carbon::Check
 
 #endif  // CARBON_TOOLCHAIN_CHECK_DEDUCE_H_

+ 27 - 14
toolchain/check/handle_impl.cpp

@@ -55,14 +55,14 @@ auto HandleParseNode(Context& context, Parse::ImplForallId node_id) -> bool {
 
 auto HandleParseNode(Context& context, Parse::TypeImplAsId node_id) -> bool {
   auto [self_node, self_id] = context.node_stack().PopExprWithNodeId();
-  auto [self_inst_id, self_type_id] = ExprAsType(context, self_node, self_id);
-  context.node_stack().Push(node_id, self_type_id);
+  self_id = ExprAsType(context, self_node, self_id).inst_id;
+  context.node_stack().Push(node_id, self_id);
 
   // Introduce `Self`. Note that we add this name lexically rather than adding
   // to the `NameScopeId` of the `impl`, because this happens before we enter
   // the `impl` scope or even identify which `impl` we're declaring.
   // TODO: Revisit this once #3714 is resolved.
-  context.AddNameToLookup(SemIR::NameId::SelfType, self_inst_id);
+  context.AddNameToLookup(SemIR::NameId::SelfType, self_id);
   return true;
 }
 
@@ -103,9 +103,21 @@ auto HandleParseNode(Context& context, Parse::DefaultSelfImplAsId node_id)
     self_type_id = SemIR::TypeId::Error;
   }
 
+  // Build the implicit access to the enclosing `Self`.
+  // TODO: Consider calling `HandleNameAsExpr` to build this implicit `Self`
+  // expression. We've already done the work to check that the enclosing context
+  // is a class and found its `Self`, so additionally performing an unqualified
+  // name lookup would be redundant work, but would avoid duplicating the
+  // handling of the `Self` expression.
+  auto self_inst_id = context.AddInst(
+      node_id,
+      SemIR::NameRef{.type_id = SemIR::TypeId::TypeType,
+                     .name_id = SemIR::NameId::SelfType,
+                     .value_id = context.types().GetInstId(self_type_id)});
+
   // There's no need to push `Self` into scope here, because we can find it in
   // the parent class scope.
-  context.node_stack().Push(node_id, self_type_id);
+  context.node_stack().Push(node_id, self_inst_id);
   return true;
 }
 
@@ -241,16 +253,17 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId node_id,
     -> std::pair<SemIR::ImplId, SemIR::InstId> {
   auto [constraint_node, constraint_id] =
       context.node_stack().PopExprWithNodeId();
-  auto [self_type_node, self_type_id] =
+  auto [self_type_node, self_inst_id] =
       context.node_stack().PopWithNodeId<Parse::NodeCategory::ImplAs>();
+  auto self_type_id = context.GetTypeIdForTypeInst(self_inst_id);
   // Pop the `impl` introducer and any `forall` parameters as a "name".
   auto name = PopImplIntroducerAndParamsAsNameComponent(context, node_id);
   auto decl_block_id = context.inst_block_stack().Pop();
 
   // Convert the constraint expression to a type.
   // TODO: Check that its constant value is a constraint.
-  auto constraint_type_id =
-      ExprAsType(context, constraint_node, constraint_id).type_id;
+  auto [constraint_inst_id, constraint_type_id] =
+      ExprAsType(context, constraint_node, constraint_id);
 
   // Process modifiers.
   // TODO: Should we somehow permit access specifiers on `impl`s?
@@ -276,11 +289,10 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId node_id,
       name_context.MakeEntityWithParamsBase(name, impl_decl_id,
                                             /*is_extern=*/false,
                                             SemIR::LibraryNameId::Invalid),
-      {.self_id = self_type_id, .constraint_id = constraint_type_id}};
+      {.self_id = self_inst_id, .constraint_id = constraint_inst_id}};
 
   // Add the impl declaration.
-  auto lookup_bucket_ref = context.impls().GetOrAddLookupBucket(
-      impl_info.self_id, impl_info.constraint_id);
+  auto lookup_bucket_ref = context.impls().GetOrAddLookupBucket(impl_info);
   for (auto prev_impl_id : lookup_bucket_ref) {
     if (MergeImplRedecl(context, impl_info, prev_impl_id)) {
       impl_decl.impl_id = prev_impl_id;
@@ -329,13 +341,14 @@ auto HandleParseNode(Context& context, Parse::ImplDefinitionStartId node_id)
 
   if (impl_info.is_defined()) {
     CARBON_DIAGNOSTIC(ImplRedefinition, Error,
-                      "redefinition of `impl {0} as {1}`", SemIR::TypeId,
-                      SemIR::TypeId);
+                      "redefinition of `impl {0} as {1}`", std::string,
+                      std::string);
     CARBON_DIAGNOSTIC(ImplPreviousDefinition, Note,
                       "previous definition was here");
     context.emitter()
-        .Build(node_id, ImplRedefinition, impl_info.self_id,
-               impl_info.constraint_id)
+        .Build(node_id, ImplRedefinition,
+               context.sem_ir().StringifyTypeExpr(impl_info.self_id),
+               context.sem_ir().StringifyTypeExpr(impl_info.constraint_id))
         .Note(impl_info.definition_id, ImplPreviousDefinition)
         .Emit();
   } else {

+ 5 - 3
toolchain/check/impl.cpp

@@ -139,6 +139,7 @@ static auto BuildInterfaceWitness(
   }
 
   auto& impl_scope = context.name_scopes().Get(impl.scope_id);
+  auto self_type_id = context.GetTypeIdForTypeInst(impl.self_id);
 
   llvm::SmallVector<SemIR::InstId> table;
   auto assoc_entities =
@@ -168,7 +169,7 @@ static auto BuildInterfaceWitness(
         if (impl_decl_id.is_valid()) {
           used_decl_ids.push_back(impl_decl_id);
           table.push_back(CheckAssociatedFunctionImplementation(
-              context, *fn_type, impl_decl_id, impl.self_id));
+              context, *fn_type, impl_decl_id, self_type_id));
         } else {
           CARBON_DIAGNOSTIC(
               ImplMissingFunction, Error,
@@ -210,8 +211,9 @@ auto BuildImplWitness(Context& context, SemIR::ImplId impl_id)
   CARBON_CHECK(impl.is_being_defined());
 
   // TODO: Handle non-interface constraints.
+  auto interface_type_id = context.GetTypeIdForTypeInst(impl.constraint_id);
   auto interface_type =
-      context.types().TryGetAs<SemIR::InterfaceType>(impl.constraint_id);
+      context.types().TryGetAs<SemIR::InterfaceType>(interface_type_id);
   if (!interface_type) {
     context.TODO(impl.definition_id, "impl as non-interface");
     return SemIR::InstId::BuiltinError;
@@ -219,7 +221,7 @@ auto BuildImplWitness(Context& context, SemIR::ImplId impl_id)
 
   llvm::SmallVector<SemIR::InstId> used_decl_ids;
 
-  auto witness_id = BuildInterfaceWitness(context, impl, impl.constraint_id,
+  auto witness_id = BuildInterfaceWitness(context, impl, interface_type_id,
                                           *interface_type, used_decl_ids);
 
   // TODO: Diagnose if any declarations in the impl are not in used_decl_ids.

+ 48 - 21
toolchain/check/import_ref.cpp

@@ -56,7 +56,8 @@ auto AddImportIR(Context& context, SemIR::ImportIR import_ir)
 }
 
 auto AddImportRef(Context& context, SemIR::ImportIRInst import_ir_inst,
-                  SemIR::EntityNameId entity_name_id) -> SemIR::InstId {
+                  SemIR::EntityNameId entity_name_id =
+                      SemIR::EntityNameId::Invalid) -> SemIR::InstId {
   auto import_ir_inst_id = context.import_ir_insts().Add(import_ir_inst);
   SemIR::ImportRefUnloaded inst = {.import_ir_inst_id = import_ir_inst_id,
                                    .entity_name_id = entity_name_id};
@@ -70,6 +71,29 @@ auto AddImportRef(Context& context, SemIR::ImportIRInst import_ir_inst,
   return import_ref_id;
 }
 
+// Adds an import_ref instruction for an instruction that we have already loaded
+// from an imported IR, with a known constant value. This is useful when the
+// instruction has a symbolic constant value, in order to produce an instruction
+// that hold that symbolic constant.
+static auto AddLoadedImportRef(Context& context,
+                               SemIR::ImportIRInst import_ir_inst,
+                               SemIR::TypeId type_id,
+                               SemIR::ConstantId const_id) -> SemIR::InstId {
+  auto import_ir_inst_id = context.import_ir_insts().Add(import_ir_inst);
+  SemIR::ImportRefLoaded inst = {
+      .type_id = type_id,
+      .import_ir_inst_id = import_ir_inst_id,
+      .entity_name_id = SemIR::EntityNameId::Invalid};
+  auto inst_id = context.AddPlaceholderInstInNoBlock(
+      context.MakeImportedLocAndInst(import_ir_inst_id, inst));
+  context.import_ref_ids().push_back(inst_id);
+
+  context.constant_values().Set(inst_id, const_id);
+  context.import_ir_constant_values()[import_ir_inst.ir_id.index].Set(
+      import_ir_inst.inst_id, const_id);
+  return inst_id;
+}
+
 auto GetCanonicalImportIRInst(Context& context, const SemIR::File* cursor_ir,
                               SemIR::InstId cursor_inst_id)
     -> SemIR::ImportIRInst {
@@ -115,8 +139,7 @@ auto VerifySameCanonicalImportIRInst(Context& context, SemIR::InstId prev_id,
     return;
   }
   auto conflict_id =
-      AddImportRef(context, {.ir_id = new_ir_id, .inst_id = new_inst_id},
-                   SemIR::EntityNameId::Invalid);
+      AddImportRef(context, {.ir_id = new_ir_id, .inst_id = new_inst_id});
   context.DiagnoseDuplicateName(conflict_id, prev_id);
 }
 
@@ -902,8 +925,7 @@ class ImportRefResolver {
                               SemIR::NameScope& new_scope) -> void {
     for (auto entry : import_scope.names) {
       auto ref_id = AddImportRef(
-          context_, {.ir_id = import_ir_id_, .inst_id = entry.inst_id},
-          SemIR::EntityNameId::Invalid);
+          context_, {.ir_id = import_ir_id_, .inst_id = entry.inst_id});
       new_scope.AddRequired({.name_id = GetLocalNameId(entry.name_id),
                              .inst_id = ref_id,
                              .access_kind = entry.access_kind});
@@ -923,8 +945,7 @@ class ImportRefResolver {
     new_associated_entities.reserve(associated_entities.size());
     for (auto inst_id : associated_entities) {
       new_associated_entities.push_back(
-          AddImportRef(context_, {.ir_id = import_ir_id_, .inst_id = inst_id},
-                       SemIR::EntityNameId::Invalid));
+          AddImportRef(context_, {.ir_id = import_ir_id_, .inst_id = inst_id}));
     }
     return context_.inst_blocks().Add(new_associated_entities);
   }
@@ -1143,8 +1164,7 @@ class ImportRefResolver {
 
     // Add a lazy reference to the target declaration.
     auto decl_id = AddImportRef(
-        context_, {.ir_id = import_ir_id_, .inst_id = inst.decl_id},
-        SemIR::EntityNameId::Invalid);
+        context_, {.ir_id = import_ir_id_, .inst_id = inst.decl_id});
 
     return ResolveAs<SemIR::AssociatedEntity>(
         {.type_id = context_.GetTypeIdForTypeConstant(type_const_id),
@@ -1589,8 +1609,8 @@ class ImportRefResolver {
             AddImportIRInst(import_impl.latest_decl_id()), impl_decl));
     impl_decl.impl_id = context_.impls().Add(
         {GetIncompleteLocalEntityBase(impl_decl_id, import_impl),
-         {.self_id = SemIR::TypeId::Invalid,
-          .constraint_id = SemIR::TypeId::Invalid,
+         {.self_id = SemIR::InstId::Invalid,
+          .constraint_id = SemIR::InstId::Invalid,
           .witness_id = SemIR::InstId::Invalid}});
 
     // Write the impl ID into the ImplDecl.
@@ -1654,8 +1674,10 @@ class ImportRefResolver {
     auto parent_scope_id = GetLocalNameScopeId(import_impl.parent_scope_id);
     LoadLocalParamConstantIds(import_impl.implicit_param_refs_id);
     auto generic_data = GetLocalGenericData(import_impl.generic_id);
-    auto self_const_id = GetLocalConstantId(import_impl.self_id);
-    auto constraint_const_id = GetLocalConstantId(import_impl.constraint_id);
+    auto self_const_id = GetLocalConstantId(
+        import_ir_.constant_values().Get(import_impl.self_id));
+    auto constraint_const_id = GetLocalConstantId(
+        import_ir_.constant_values().Get(import_impl.constraint_id));
 
     if (HasNewWork()) {
       return Retry(impl_const_id);
@@ -1668,14 +1690,21 @@ class ImportRefResolver {
     CARBON_CHECK(!import_impl.param_refs_id.is_valid() &&
                  !new_impl.param_refs_id.is_valid());
     SetGenericData(import_impl.generic_id, new_impl.generic_id, generic_data);
-    new_impl.self_id = context_.GetTypeIdForTypeConstant(self_const_id);
-    new_impl.constraint_id =
-        context_.GetTypeIdForTypeConstant(constraint_const_id);
+
+    // Create instructions for self and constraint to hold the symbolic constant
+    // value for a generic impl.
+    new_impl.self_id = AddLoadedImportRef(
+        context_, {.ir_id = import_ir_id_, .inst_id = import_impl.self_id},
+        SemIR::TypeId::TypeType, self_const_id);
+    new_impl.constraint_id = AddLoadedImportRef(
+        context_,
+        {.ir_id = import_ir_id_, .inst_id = import_impl.constraint_id},
+        SemIR::TypeId::TypeType, constraint_const_id);
 
     if (import_impl.is_defined()) {
       auto witness_id = AddImportRef(
-          context_, {.ir_id = import_ir_id_, .inst_id = import_impl.witness_id},
-          SemIR::EntityNameId::Invalid);
+          context_,
+          {.ir_id = import_ir_id_, .inst_id = import_impl.witness_id});
       AddImplDefinition(import_impl, new_impl, witness_id);
     }
 
@@ -1683,9 +1712,7 @@ class ImportRefResolver {
     // file, add this to impl lookup so that it can be found by redeclarations
     // in the current file.
     if (import_ir_id_ == SemIR::ImportIRId::ApiForImpl) {
-      context_.impls()
-          .GetOrAddLookupBucket(new_impl.self_id, new_impl.constraint_id)
-          .push_back(impl_id);
+      context_.impls().GetOrAddLookupBucket(new_impl).push_back(impl_id);
     }
 
     return ResolveAsConstant(impl_const_id);

+ 22 - 7
toolchain/check/member_access.cpp

@@ -10,6 +10,7 @@
 #include "toolchain/base/kind_switch.h"
 #include "toolchain/check/context.h"
 #include "toolchain/check/convert.h"
+#include "toolchain/check/deduce.h"
 #include "toolchain/check/import_ref.h"
 #include "toolchain/diagnostics/diagnostic_emitter.h"
 #include "toolchain/sem_ir/generic.h"
@@ -177,18 +178,30 @@ static auto ScopeNeedsImplLookup(Context& context, LookupScope scope) -> bool {
 // Returns an invalid InstId if no matching impl is found.
 static auto LookupInterfaceWitness(Context& context,
                                    SemIR::ConstantId type_const_id,
-                                   SemIR::TypeId interface_type_id)
+                                   SemIR::ConstantId interface_const_id)
     -> SemIR::InstId {
   // TODO: Add a better impl lookup system. At the very least, we should only be
   // considering impls that are for the same interface we're querying. We can
   // also skip impls that mention any types that aren't part of our impl query.
   for (const auto& impl : context.impls().array_ref()) {
+    auto specific_id = SemIR::SpecificId::Invalid;
+    if (impl.generic_id.is_valid()) {
+      specific_id =
+          DeduceImplArguments(context, impl, type_const_id, interface_const_id);
+      if (!specific_id.is_valid()) {
+        continue;
+      }
+    }
     if (!context.constant_values().AreEqualAcrossDeclarations(
-            context.types().GetConstantId(impl.self_id), type_const_id)) {
+            SemIR::GetConstantValueInSpecific(context.sem_ir(), specific_id,
+                                              impl.self_id),
+            type_const_id)) {
       continue;
     }
-    if (!context.types().AreEqualAcrossDeclarations(impl.constraint_id,
-                                                    interface_type_id)) {
+    if (!context.constant_values().AreEqualAcrossDeclarations(
+            SemIR::GetConstantValueInSpecific(context.sem_ir(), specific_id,
+                                              impl.constraint_id),
+            interface_const_id)) {
       // TODO: An impl of a constraint type should be treated as implementing
       // the constraint's interfaces.
       continue;
@@ -198,7 +211,9 @@ static auto LookupInterfaceWitness(Context& context,
       return SemIR::InstId::Invalid;
     }
     LoadImportRef(context, impl.witness_id);
-    return impl.witness_id;
+    return context.constant_values().GetInstId(
+        SemIR::GetConstantValueInSpecific(context.sem_ir(), specific_id,
+                                          impl.witness_id));
   }
   return SemIR::InstId::Invalid;
 }
@@ -213,8 +228,8 @@ static auto PerformImplLookup(
   auto interface_type =
       context.types().GetAs<SemIR::InterfaceType>(assoc_type.interface_type_id);
   auto& interface = context.interfaces().Get(interface_type.interface_id);
-  auto witness_id = LookupInterfaceWitness(context, type_const_id,
-                                           assoc_type.interface_type_id);
+  auto witness_id = LookupInterfaceWitness(
+      context, type_const_id, assoc_type.interface_type_id.AsConstantId());
   if (!witness_id.is_valid()) {
     if (missing_impl_diagnoser) {
       CARBON_DIAGNOSTIC(MissingImplInMemberAccessNote, Note,

+ 1 - 1
toolchain/check/node_stack.h

@@ -391,7 +391,7 @@ class NodeStack {
     set_id_if_category_is(Parse::NodeCategory::MemberName,
                           Id::KindFor<SemIR::NameId>());
     set_id_if_category_is(Parse::NodeCategory::ImplAs,
-                          Id::KindFor<SemIR::TypeId>());
+                          Id::KindFor<SemIR::InstId>());
     set_id_if_category_is(Parse::NodeCategory::Decl |
                               Parse::NodeCategory::Statement |
                               Parse::NodeCategory::Modifier,

+ 4 - 4
toolchain/check/testdata/as/overloaded.carbon

@@ -136,7 +136,7 @@ let n: i32 = ((4 as i32) as X) as i32;
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.1: i32 as %.8 {
+// CHECK:STDOUT: impl @impl.1: %.loc15_6.2 as %.loc15_20 {
 // CHECK:STDOUT:   %Convert.decl: %Convert.type.2 = fn_decl @Convert.2 [template = constants.%Convert.2] {
 // CHECK:STDOUT:     %self.patt: i32 = binding_pattern self
 // CHECK:STDOUT:   } {
@@ -155,7 +155,7 @@ let n: i32 = ((4 as i32) as X) as i32;
 // CHECK:STDOUT:   witness = %.loc15_24
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.2: %X as %.13 {
+// CHECK:STDOUT: impl @impl.2: %X.ref as %.loc19_18.3 {
 // CHECK:STDOUT:   %Convert.decl: %Convert.type.4 = fn_decl @Convert.3 [template = constants.%Convert.4] {
 // CHECK:STDOUT:     %self.patt: %X = binding_pattern self
 // CHECK:STDOUT:   } {
@@ -226,7 +226,7 @@ let n: i32 = ((4 as i32) as X) as i32;
 // CHECK:STDOUT:   %.loc23_26.1: type = interface_type @As, @As(constants.%X) [template = constants.%.8]
 // CHECK:STDOUT:   %.loc23_26.2: %.9 = specific_constant imports.%import_ref.4, @As(constants.%X) [template = constants.%.10]
 // CHECK:STDOUT:   %Convert.ref.loc23_26: %.9 = name_ref Convert, %.loc23_26.2 [template = constants.%.10]
-// CHECK:STDOUT:   %.loc23_26.3: %Convert.type.3 = interface_witness_access @impl.1.%.loc15_24, element0 [template = constants.%Convert.2]
+// CHECK:STDOUT:   %.loc23_26.3: %Convert.type.3 = interface_witness_access constants.%.11, element0 [template = constants.%Convert.2]
 // CHECK:STDOUT:   %.loc23_26.4: <bound method> = bound_method %.loc23_16, %.loc23_26.3 [template = constants.%.19]
 // CHECK:STDOUT:   %.loc23_26.5: ref %X = temporary_storage
 // CHECK:STDOUT:   %Convert.call.loc23_26: init %X = call %.loc23_26.4(%.loc23_16) to %.loc23_26.5
@@ -238,7 +238,7 @@ let n: i32 = ((4 as i32) as X) as i32;
 // CHECK:STDOUT:   %.loc23_32.2: %.14 = specific_constant imports.%import_ref.4, @As(i32) [template = constants.%.15]
 // CHECK:STDOUT:   %Convert.ref.loc23_32: %.14 = name_ref Convert, %.loc23_32.2 [template = constants.%.15]
 // CHECK:STDOUT:   %.loc23_26.7: ref %X = temporary %.loc23_26.5, %.loc23_26.6
-// CHECK:STDOUT:   %.loc23_32.3: %Convert.type.5 = interface_witness_access @impl.2.%.loc19_24, element0 [template = constants.%Convert.4]
+// CHECK:STDOUT:   %.loc23_32.3: %Convert.type.5 = interface_witness_access constants.%.16, element0 [template = constants.%Convert.4]
 // CHECK:STDOUT:   %.loc23_32.4: <bound method> = bound_method %.loc23_26.7, %.loc23_32.3
 // CHECK:STDOUT:   %.loc23_26.8: %X = bind_value %.loc23_26.7
 // CHECK:STDOUT:   %Convert.call.loc23_32: init i32 = call %.loc23_32.4(%.loc23_26.8)

+ 2 - 2
toolchain/check/testdata/function/builtin/method.carbon

@@ -74,7 +74,7 @@ var arr: [i32; 1.(I.F)(2)];
 // CHECK:STDOUT:   %.loc19_16: i32 = int_literal 1 [template = constants.%.6]
 // CHECK:STDOUT:   %I.ref: type = name_ref I, %I.decl [template = constants.%.1]
 // CHECK:STDOUT:   %F.ref: %.3 = name_ref F, @I.%.loc12 [template = constants.%.4]
-// CHECK:STDOUT:   %.loc19_17.1: %F.type.1 = interface_witness_access @impl.%.loc15_15, element0 [template = constants.%F.2]
+// CHECK:STDOUT:   %.loc19_17.1: %F.type.1 = interface_witness_access constants.%.5, element0 [template = constants.%F.2]
 // CHECK:STDOUT:   %.loc19_17.2: <bound method> = bound_method %.loc19_16, %.loc19_17.1 [template = constants.%.7]
 // CHECK:STDOUT:   %.loc19_24: i32 = int_literal 2 [template = constants.%.8]
 // CHECK:STDOUT:   %int.sadd: init i32 = call %.loc19_17.2(%.loc19_16, %.loc19_24) [template = constants.%.9]
@@ -114,7 +114,7 @@ var arr: [i32; 1.(I.F)(2)];
 // CHECK:STDOUT:   witness = (%F.decl)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: i32 as %.1 {
+// CHECK:STDOUT: impl @impl: %.loc15_6.2 as %I.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {
 // CHECK:STDOUT:     %self.patt: i32 = binding_pattern self
 // CHECK:STDOUT:     %other.patt: i32 = binding_pattern other

+ 3 - 3
toolchain/check/testdata/function/builtin/no_prelude/call_from_operator.carbon

@@ -156,7 +156,7 @@ var arr: [i32; 1 + 2] = (3, 4, 3 + 4);
 // CHECK:STDOUT:   %.loc10_16: i32 = int_literal 1 [template = constants.%.4]
 // CHECK:STDOUT:   %.loc10_20: i32 = int_literal 2 [template = constants.%.5]
 // CHECK:STDOUT:   %Op.ref: %.6 = name_ref Op, imports.%import_ref.4 [template = constants.%.7]
-// CHECK:STDOUT:   %.loc10_18.1: %Op.type.2 = interface_witness_access @impl.%.loc6_22, element0 [template = constants.%Op.1]
+// CHECK:STDOUT:   %.loc10_18.1: %Op.type.2 = interface_witness_access constants.%.3, element0 [template = constants.%Op.1]
 // CHECK:STDOUT:   %.loc10_18.2: <bound method> = bound_method %.loc10_16, %.loc10_18.1 [template = constants.%.8]
 // CHECK:STDOUT:   %int.sadd: init i32 = call %.loc10_18.2(%.loc10_16, %.loc10_20) [template = constants.%.9]
 // CHECK:STDOUT:   %.loc10_11.1: type = value_of_initializer %int.make_type_32 [template = i32]
@@ -173,7 +173,7 @@ var arr: [i32; 1 + 2] = (3, 4, 3 + 4);
 // CHECK:STDOUT:   witness = (imports.%import_ref.5)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: i32 as %.2 {
+// CHECK:STDOUT: impl @impl: %.loc6_6.2 as %Add.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.1 = fn_decl @Op.1 [template = constants.%Op.1] {
 // CHECK:STDOUT:     %self.patt: i32 = binding_pattern self
 // CHECK:STDOUT:     %other.patt: i32 = binding_pattern other
@@ -211,7 +211,7 @@ var arr: [i32; 1 + 2] = (3, 4, 3 + 4);
 // CHECK:STDOUT:   %.loc10_32: i32 = int_literal 3 [template = constants.%.9]
 // CHECK:STDOUT:   %.loc10_36: i32 = int_literal 4 [template = constants.%.12]
 // CHECK:STDOUT:   %Op.ref: %.6 = name_ref Op, imports.%import_ref.4 [template = constants.%.7]
-// CHECK:STDOUT:   %.loc10_34.1: %Op.type.2 = interface_witness_access @impl.%.loc6_22, element0 [template = constants.%Op.1]
+// CHECK:STDOUT:   %.loc10_34.1: %Op.type.2 = interface_witness_access constants.%.3, element0 [template = constants.%Op.1]
 // CHECK:STDOUT:   %.loc10_34.2: <bound method> = bound_method %.loc10_32, %.loc10_34.1 [template = constants.%.13]
 // CHECK:STDOUT:   %int.sadd: init i32 = call %.loc10_34.2(%.loc10_32, %.loc10_36) [template = constants.%.14]
 // CHECK:STDOUT:   %.loc10_37.1: %.15 = tuple_literal (%.loc10_26, %.loc10_29, %int.sadd)

+ 5 - 5
toolchain/check/testdata/impl/compound.carbon

@@ -160,7 +160,7 @@ fn InstanceCallIndirect(p: i32*) {
 // CHECK:STDOUT:   witness = (%F.decl, %G.decl)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: i32 as %.1 {
+// CHECK:STDOUT: impl @impl: %.loc16_6.2 as %Simple.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {} {}
 // CHECK:STDOUT:   %G.decl: %G.type.2 = fn_decl @G.2 [template = constants.%G.2] {
 // CHECK:STDOUT:     %self.patt: i32 = binding_pattern self
@@ -201,7 +201,7 @@ fn InstanceCallIndirect(p: i32*) {
 // CHECK:STDOUT:   %n.ref: i32 = name_ref n, %n
 // CHECK:STDOUT:   %Simple.ref: type = name_ref Simple, file.%Simple.decl [template = constants.%.1]
 // CHECK:STDOUT:   %F.ref: %.3 = name_ref F, @Simple.%.loc12 [template = constants.%.4]
-// CHECK:STDOUT:   %.loc22: %F.type.1 = interface_witness_access @impl.%.loc16_20, element0 [template = constants.%F.2]
+// CHECK:STDOUT:   %.loc22: %F.type.1 = interface_witness_access constants.%.7, element0 [template = constants.%F.2]
 // CHECK:STDOUT:   %F.call: init %.2 = call %.loc22()
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
@@ -211,7 +211,7 @@ fn InstanceCallIndirect(p: i32*) {
 // CHECK:STDOUT:   %n.ref: i32 = name_ref n, %n
 // CHECK:STDOUT:   %Simple.ref: type = name_ref Simple, file.%Simple.decl [template = constants.%.1]
 // CHECK:STDOUT:   %G.ref: %.5 = name_ref G, @Simple.%.loc13 [template = constants.%.6]
-// CHECK:STDOUT:   %.loc26_4.1: %G.type.1 = interface_witness_access @impl.%.loc16_20, element1 [template = constants.%G.2]
+// CHECK:STDOUT:   %.loc26_4.1: %G.type.1 = interface_witness_access constants.%.7, element1 [template = constants.%G.2]
 // CHECK:STDOUT:   %.loc26_4.2: <bound method> = bound_method %n.ref, %.loc26_4.1
 // CHECK:STDOUT:   %G.call: init %.2 = call %.loc26_4.2(%n.ref)
 // CHECK:STDOUT:   return
@@ -223,7 +223,7 @@ fn InstanceCallIndirect(p: i32*) {
 // CHECK:STDOUT:   %Simple.ref: type = name_ref Simple, file.%Simple.decl [template = constants.%.1]
 // CHECK:STDOUT:   %F.ref: %.3 = name_ref F, @Simple.%.loc12 [template = constants.%.4]
 // CHECK:STDOUT:   %.loc30_4.1: ref i32 = deref %p.ref
-// CHECK:STDOUT:   %.loc30_4.2: %F.type.1 = interface_witness_access @impl.%.loc16_20, element0 [template = constants.%F.2]
+// CHECK:STDOUT:   %.loc30_4.2: %F.type.1 = interface_witness_access constants.%.7, element0 [template = constants.%F.2]
 // CHECK:STDOUT:   %F.call: init %.2 = call %.loc30_4.2()
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
@@ -234,7 +234,7 @@ fn InstanceCallIndirect(p: i32*) {
 // CHECK:STDOUT:   %Simple.ref: type = name_ref Simple, file.%Simple.decl [template = constants.%.1]
 // CHECK:STDOUT:   %G.ref: %.5 = name_ref G, @Simple.%.loc13 [template = constants.%.6]
 // CHECK:STDOUT:   %.loc34_4.1: ref i32 = deref %p.ref
-// CHECK:STDOUT:   %.loc34_4.2: %G.type.1 = interface_witness_access @impl.%.loc16_20, element1 [template = constants.%G.2]
+// CHECK:STDOUT:   %.loc34_4.2: %G.type.1 = interface_witness_access constants.%.7, element1 [template = constants.%G.2]
 // CHECK:STDOUT:   %.loc34_4.3: <bound method> = bound_method %.loc34_4.1, %.loc34_4.2
 // CHECK:STDOUT:   %.loc34_4.4: i32 = bind_value %.loc34_4.1
 // CHECK:STDOUT:   %G.call: init %.2 = call %.loc34_4.3(%.loc34_4.4)

+ 1 - 1
toolchain/check/testdata/impl/declaration.carbon

@@ -60,7 +60,7 @@ impl i32 as I;
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: i32 as %.1;
+// CHECK:STDOUT: impl @impl: %.loc13_6.2 as %I.ref;
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32";
 // CHECK:STDOUT:

+ 1 - 1
toolchain/check/testdata/impl/empty.carbon

@@ -63,7 +63,7 @@ impl i32 as Empty {
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: i32 as %.1 {
+// CHECK:STDOUT: impl @impl: %.loc14_6.2 as %Empty.ref {
 // CHECK:STDOUT:   %.loc14_19: <witness> = interface_witness () [template = constants.%.3]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:

+ 4 - 3
toolchain/check/testdata/impl/extend_impl.carbon

@@ -87,7 +87,7 @@ fn G(c: C) {
 // CHECK:STDOUT:   witness = (%F.decl)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.1 {
+// CHECK:STDOUT: impl @impl: %Self.ref as %HasF.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {} {}
 // CHECK:STDOUT:   %.loc16: <witness> = interface_witness (%F.decl) [template = constants.%.5]
 // CHECK:STDOUT:
@@ -98,6 +98,7 @@ fn G(c: C) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT:   impl_decl @impl [template] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%C [template = constants.%C]
 // CHECK:STDOUT:     %HasF.ref: type = name_ref HasF, file.%HasF.decl [template = constants.%.1]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc19: <witness> = complete_type_witness %.6 [template = constants.%.7]
@@ -121,11 +122,11 @@ fn G(c: C) {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %C.ref.loc22: type = name_ref C, file.%C.decl [template = constants.%C]
 // CHECK:STDOUT:   %F.ref.loc22: %.3 = name_ref F, @HasF.%.loc12 [template = constants.%.4]
-// CHECK:STDOUT:   %.loc22: %F.type.1 = interface_witness_access @impl.%.loc16, element0 [template = constants.%F.2]
+// CHECK:STDOUT:   %.loc22: %F.type.1 = interface_witness_access constants.%.5, element0 [template = constants.%F.2]
 // CHECK:STDOUT:   %F.call.loc22: init %.2 = call %.loc22()
 // CHECK:STDOUT:   %c.ref: %C = name_ref c, %c
 // CHECK:STDOUT:   %F.ref.loc23: %.3 = name_ref F, @HasF.%.loc12 [template = constants.%.4]
-// CHECK:STDOUT:   %.loc23: %F.type.1 = interface_witness_access @impl.%.loc16, element0 [template = constants.%F.2]
+// CHECK:STDOUT:   %.loc23: %F.type.1 = interface_witness_access constants.%.5, element0 [template = constants.%F.2]
 // CHECK:STDOUT:   %F.call.loc23: init %.2 = call %.loc23()
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }

+ 2 - 2
toolchain/check/testdata/impl/fail_call_invalid.carbon

@@ -100,7 +100,7 @@ fn InstanceCall(n: i32) {
 // CHECK:STDOUT:   witness = (%G.decl)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: i32 as %.1 {
+// CHECK:STDOUT: impl @impl: %.loc15_6.2 as %Simple.ref {
 // CHECK:STDOUT:   %G.decl: %G.type.2 = fn_decl @G.2 [template = constants.%G.2] {
 // CHECK:STDOUT:     %self.patt: <error> = binding_pattern self
 // CHECK:STDOUT:   } {
@@ -130,7 +130,7 @@ fn InstanceCall(n: i32) {
 // CHECK:STDOUT:   %n.ref: i32 = name_ref n, %n
 // CHECK:STDOUT:   %Simple.ref: type = name_ref Simple, file.%Simple.decl [template = constants.%.1]
 // CHECK:STDOUT:   %G.ref: %.3 = name_ref G, @Simple.%.loc12 [template = constants.%.4]
-// CHECK:STDOUT:   %.loc23_4.1: %G.type.1 = interface_witness_access @impl.%.loc15_20, element0 [template = <error>]
+// CHECK:STDOUT:   %.loc23_4.1: %G.type.1 = interface_witness_access <error>, element0 [template = <error>]
 // CHECK:STDOUT:   %.loc23_4.2: <bound method> = bound_method %n.ref, %.loc23_4.1
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }

+ 2 - 1
toolchain/check/testdata/impl/fail_extend_impl_forall.carbon

@@ -104,7 +104,7 @@ class C {
 // CHECK:STDOUT:   %T.1: type = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T)]
 // CHECK:STDOUT:   %.1: type = interface_type @GenericInterface, @GenericInterface(%T.1) [symbolic = %.1 (constants.%.2)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   impl: %C as %.2 {
+// CHECK:STDOUT:   impl: %Self.ref as %.loc19_52 {
 // CHECK:STDOUT:     %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {
 // CHECK:STDOUT:       %x.patt: @F.2.%T (%T) = binding_pattern x
 // CHECK:STDOUT:     } {
@@ -126,6 +126,7 @@ class C {
 // CHECK:STDOUT:   } {
 // CHECK:STDOUT:     %T.param: type = param T, runtime_param<invalid>
 // CHECK:STDOUT:     %T.loc19: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%C [template = constants.%C]
 // CHECK:STDOUT:     %GenericInterface.ref: %GenericInterface.type = name_ref GenericInterface, file.%GenericInterface.decl [template = constants.%GenericInterface]
 // CHECK:STDOUT:     %T.ref: type = name_ref T, %T.loc19 [symbolic = %T.1 (constants.%T)]
 // CHECK:STDOUT:     %.loc19_52: type = interface_type @GenericInterface, @GenericInterface(constants.%T) [symbolic = %.1 (constants.%.2)]

+ 1 - 1
toolchain/check/testdata/impl/fail_extend_impl_scope.carbon

@@ -64,7 +64,7 @@ extend impl i32 as I {}
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: i32 as %.1 {
+// CHECK:STDOUT: impl @impl: %.loc16_13.2 as %I.ref {
 // CHECK:STDOUT:   %.loc16_22: <witness> = interface_witness () [template = constants.%.3]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:

+ 3 - 3
toolchain/check/testdata/impl/fail_extend_impl_type_as.carbon

@@ -93,16 +93,16 @@ class E {
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.1: i32 as %.1 {
+// CHECK:STDOUT: impl @impl.1: %.loc18_15.2 as %I.ref {
 // CHECK:STDOUT:   %.loc18_24: <witness> = interface_witness () [template = constants.%.3]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   witness = %.loc18_24
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.2: %D as %.1;
+// CHECK:STDOUT: impl @impl.2: %D.ref as %I.ref;
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.3: %E as %.1 {
+// CHECK:STDOUT: impl @impl.3: %Self.ref as %I.ref {
 // CHECK:STDOUT:   %.loc39: <witness> = interface_witness () [template = constants.%.3]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:

+ 2 - 1
toolchain/check/testdata/impl/fail_extend_non_interface.carbon

@@ -50,12 +50,13 @@ class C {
 // CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {} {}
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as i32;
+// CHECK:STDOUT: impl @impl: %Self.ref as @C.%.loc15_18.2;
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT:   %.loc15_18.1: type = value_of_initializer @impl.%int.make_type_32 [template = i32]
 // CHECK:STDOUT:   %.loc15_18.2: type = converted @impl.%int.make_type_32, %.loc15_18.1 [template = i32]
 // CHECK:STDOUT:   impl_decl @impl [template] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%C [template = constants.%C]
 // CHECK:STDOUT:     %int.make_type_32: init type = call constants.%Int32() [template = i32]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc16: <witness> = complete_type_witness %.2 [template = constants.%.3]

+ 10 - 2
toolchain/check/testdata/impl/fail_extend_partially_defined_interface.carbon

@@ -64,8 +64,10 @@ interface I {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: generic impl @impl(@I.%Self: %.1) {
+// CHECK:STDOUT:   %Self: %.1 = bind_symbolic_name Self, 0 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:   %C: type = class_type @C, @C(%Self) [symbolic = %C (constants.%C.2)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   impl: %C.2 as %.1;
+// CHECK:STDOUT:   impl: %Self.ref as %I.ref;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: generic class @C(@I.%Self: %.1) {
@@ -73,6 +75,7 @@ interface I {
 // CHECK:STDOUT:
 // CHECK:STDOUT:   class {
 // CHECK:STDOUT:     impl_decl @impl [template] {} {
+// CHECK:STDOUT:       %Self.ref: type = name_ref Self, constants.%C.2 [symbolic = %C (constants.%C.2)]
 // CHECK:STDOUT:       %I.ref: type = name_ref I, file.%I.decl [template = constants.%.1]
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:     %.loc20: <witness> = complete_type_witness %.2 [template = constants.%.3]
@@ -85,5 +88,10 @@ interface I {
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @C(constants.%Self) {}
 // CHECK:STDOUT:
-// CHECK:STDOUT: specific @impl(constants.%Self) {}
+// CHECK:STDOUT: specific @C(@impl.%Self) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl(constants.%Self) {
+// CHECK:STDOUT:   %Self => constants.%Self
+// CHECK:STDOUT:   %C => constants.%C.2
+// CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 2 - 1
toolchain/check/testdata/impl/fail_extend_undefined_interface.carbon

@@ -55,10 +55,11 @@ class C {
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @I;
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.1;
+// CHECK:STDOUT: impl @impl: %Self.ref as %I.ref;
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT:   impl_decl @impl [template] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%C [template = constants.%C]
 // CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [template = constants.%.1]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc21: <witness> = complete_type_witness %.2 [template = constants.%.3]

+ 2 - 1
toolchain/check/testdata/impl/fail_impl_as_scope.carbon

@@ -55,6 +55,7 @@ impl as Simple {
 // CHECK:STDOUT:   %Core.import = import Core
 // CHECK:STDOUT:   %Simple.decl: type = interface_decl @Simple [template = constants.%.1] {} {}
 // CHECK:STDOUT:   impl_decl @impl [template] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, <error> [template = <error>]
 // CHECK:STDOUT:     %Simple.ref: type = name_ref Simple, file.%Simple.decl [template = constants.%.1]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
@@ -70,7 +71,7 @@ impl as Simple {
 // CHECK:STDOUT:   witness = (%F.decl)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: <error> as %.1 {
+// CHECK:STDOUT: impl @impl: %Self.ref as %Simple.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {} {}
 // CHECK:STDOUT:   %.loc18: <witness> = interface_witness (%F.decl) [template = constants.%.5]
 // CHECK:STDOUT:

+ 1 - 1
toolchain/check/testdata/impl/fail_impl_bad_assoc_const.carbon

@@ -68,7 +68,7 @@ impl bool as I {}
 // CHECK:STDOUT:   witness = (%T)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: bool as %.1 {
+// CHECK:STDOUT: impl @impl: %.loc16_6.2 as %I.ref {
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   witness = <error>
 // CHECK:STDOUT: }

+ 30 - 15
toolchain/check/testdata/impl/fail_impl_bad_assoc_fn.carbon

@@ -438,14 +438,14 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:   witness = (%F.decl)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.1: %NoF as %.1 {
+// CHECK:STDOUT: impl @impl.1: %Self.ref as %I.ref {
 // CHECK:STDOUT:   %.loc21: <witness> = interface_witness (<error>) [template = <error>]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   witness = %.loc21
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.2: %FNotFunction as %.1 {
+// CHECK:STDOUT: impl @impl.2: %Self.ref as %I.ref {
 // CHECK:STDOUT:   %F.decl: type = class_decl @F.16 [template = constants.%F.2] {} {}
 // CHECK:STDOUT:   %.loc25: <witness> = interface_witness (<error>) [template = <error>]
 // CHECK:STDOUT:
@@ -454,7 +454,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:   witness = %.loc25
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.3: %FAlias as %.1 {
+// CHECK:STDOUT: impl @impl.3: %Self.ref as %I.ref {
 // CHECK:STDOUT:   %PossiblyF.ref: %PossiblyF.type = name_ref PossiblyF, file.%PossiblyF.decl [template = constants.%PossiblyF]
 // CHECK:STDOUT:   %F: %PossiblyF.type = bind_alias F, file.%PossiblyF.decl [template = constants.%PossiblyF]
 // CHECK:STDOUT:   %.loc41: <witness> = interface_witness (<error>) [template = <error>]
@@ -464,7 +464,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:   witness = %.loc41
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.4: %FExtraParam as %.1 {
+// CHECK:STDOUT: impl @impl.4: %Self.ref as %I.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.3] {
 // CHECK:STDOUT:     %b.patt: bool = binding_pattern b
 // CHECK:STDOUT:   } {
@@ -481,7 +481,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:   witness = %.loc54
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.5: %FExtraImplicitParam as %.1 {
+// CHECK:STDOUT: impl @impl.5: %Self.ref as %I.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.3 = fn_decl @F.3 [template = constants.%F.4] {
 // CHECK:STDOUT:     %self.patt: %FExtraImplicitParam = binding_pattern self
 // CHECK:STDOUT:   } {
@@ -496,7 +496,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:   witness = %.loc67
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.6: %FExtraReturnType as %.1 {
+// CHECK:STDOUT: impl @impl.6: %Self.ref as %I.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.4 = fn_decl @F.4 [template = constants.%F.5] {} {
 // CHECK:STDOUT:     %bool.make_type: init type = call constants.%Bool() [template = bool]
 // CHECK:STDOUT:     %.loc89_15.1: type = value_of_initializer %bool.make_type [template = bool]
@@ -510,7 +510,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:   witness = %.loc81
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.7: %FMissingParam as %.7 {
+// CHECK:STDOUT: impl @impl.7: %Self.ref as %J.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.6 = fn_decl @F.6 [template = constants.%F.7] {
 // CHECK:STDOUT:     %self.patt: bool = binding_pattern self
 // CHECK:STDOUT:   } {
@@ -531,7 +531,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:   witness = %.loc96
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.8: %FMissingImplicitParam as %.7 {
+// CHECK:STDOUT: impl @impl.8: %Self.ref as %J.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.7 = fn_decl @F.7 [template = constants.%F.8] {
 // CHECK:STDOUT:     %b.patt: bool = binding_pattern b
 // CHECK:STDOUT:   } {
@@ -552,7 +552,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:   witness = %.loc109
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.9: %FMissingReturnType as %.7 {
+// CHECK:STDOUT: impl @impl.9: %Self.ref as %J.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.8 = fn_decl @F.8 [template = constants.%F.9] {
 // CHECK:STDOUT:     %self.patt: bool = binding_pattern self
 // CHECK:STDOUT:     %b.patt: bool = binding_pattern b
@@ -575,7 +575,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:   witness = %.loc122
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.10: %FDifferentParamType as %.7 {
+// CHECK:STDOUT: impl @impl.10: %Self.ref as %J.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.9 = fn_decl @F.9 [template = constants.%F.10] {
 // CHECK:STDOUT:     %self.patt: bool = binding_pattern self
 // CHECK:STDOUT:     %b.patt: %FDifferentParamType = binding_pattern b
@@ -600,7 +600,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:   witness = %.loc135
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.11: %FDifferentImplicitParamType as %.7 {
+// CHECK:STDOUT: impl @impl.11: %Self.ref as %J.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.10 = fn_decl @F.10 [template = constants.%F.11] {
 // CHECK:STDOUT:     %self.patt: %FDifferentImplicitParamType = binding_pattern self
 // CHECK:STDOUT:     %b.patt: bool = binding_pattern b
@@ -625,7 +625,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:   witness = %.loc148
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.12: %FDifferentReturnType as %.7 {
+// CHECK:STDOUT: impl @impl.12: %Self.ref as %J.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.11 = fn_decl @F.11 [template = constants.%F.12] {
 // CHECK:STDOUT:     %self.patt: bool = binding_pattern self
 // CHECK:STDOUT:     %b.patt: bool = binding_pattern b
@@ -650,7 +650,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:   witness = %.loc161
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.13: %FDifferentParamName as %.7 {
+// CHECK:STDOUT: impl @impl.13: %Self.ref as %J.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.12 = fn_decl @F.12 [template = constants.%F.13] {
 // CHECK:STDOUT:     %self.patt: bool = binding_pattern self
 // CHECK:STDOUT:     %not_b.patt: bool = binding_pattern not_b
@@ -677,7 +677,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:   witness = %.loc175
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.14: %SelfNestedBadParam as %.10 {
+// CHECK:STDOUT: impl @impl.14: %Self.ref as %SelfNested.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.14 = fn_decl @F.14 [template = constants.%F.15] {
 // CHECK:STDOUT:     %x.patt: %.21 = binding_pattern x
 // CHECK:STDOUT:   } {
@@ -706,7 +706,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:   witness = %.loc192
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.15: %SelfNestedBadReturnType as %.10 {
+// CHECK:STDOUT: impl @impl.15: %Self.ref as %SelfNested.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.15 = fn_decl @F.15 [template = constants.%F.16] {
 // CHECK:STDOUT:     %x.patt: %.27 = binding_pattern x
 // CHECK:STDOUT:   } {
@@ -735,6 +735,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @NoF {
 // CHECK:STDOUT:   impl_decl @impl.1 [template] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%NoF [template = constants.%NoF]
 // CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [template = constants.%.1]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc22: <witness> = complete_type_witness %.5 [template = constants.%.6]
@@ -745,6 +746,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @FNotFunction {
 // CHECK:STDOUT:   impl_decl @impl.2 [template] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%FNotFunction [template = constants.%FNotFunction]
 // CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [template = constants.%.1]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc35: <witness> = complete_type_witness %.5 [template = constants.%.6]
@@ -757,6 +759,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @FAlias {
 // CHECK:STDOUT:   impl_decl @impl.3 [template] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%FAlias [template = constants.%FAlias]
 // CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [template = constants.%.1]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc51: <witness> = complete_type_witness %.5 [template = constants.%.6]
@@ -767,6 +770,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @FExtraParam {
 // CHECK:STDOUT:   impl_decl @impl.4 [template] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%FExtraParam [template = constants.%FExtraParam]
 // CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [template = constants.%.1]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc64: <witness> = complete_type_witness %.5 [template = constants.%.6]
@@ -777,6 +781,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @FExtraImplicitParam {
 // CHECK:STDOUT:   impl_decl @impl.5 [template] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%FExtraImplicitParam [template = constants.%FExtraImplicitParam]
 // CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [template = constants.%.1]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc77: <witness> = complete_type_witness %.5 [template = constants.%.6]
@@ -787,6 +792,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @FExtraReturnType {
 // CHECK:STDOUT:   impl_decl @impl.6 [template] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%FExtraReturnType [template = constants.%FExtraReturnType]
 // CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [template = constants.%.1]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc91: <witness> = complete_type_witness %.5 [template = constants.%.6]
@@ -797,6 +803,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @FMissingParam {
 // CHECK:STDOUT:   impl_decl @impl.7 [template] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%FMissingParam [template = constants.%FMissingParam]
 // CHECK:STDOUT:     %J.ref: type = name_ref J, file.%J.decl [template = constants.%.7]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc106: <witness> = complete_type_witness %.5 [template = constants.%.6]
@@ -807,6 +814,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @FMissingImplicitParam {
 // CHECK:STDOUT:   impl_decl @impl.8 [template] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%FMissingImplicitParam [template = constants.%FMissingImplicitParam]
 // CHECK:STDOUT:     %J.ref: type = name_ref J, file.%J.decl [template = constants.%.7]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc119: <witness> = complete_type_witness %.5 [template = constants.%.6]
@@ -817,6 +825,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @FMissingReturnType {
 // CHECK:STDOUT:   impl_decl @impl.9 [template] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%FMissingReturnType [template = constants.%FMissingReturnType]
 // CHECK:STDOUT:     %J.ref: type = name_ref J, file.%J.decl [template = constants.%.7]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc132: <witness> = complete_type_witness %.5 [template = constants.%.6]
@@ -827,6 +836,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @FDifferentParamType {
 // CHECK:STDOUT:   impl_decl @impl.10 [template] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%FDifferentParamType [template = constants.%FDifferentParamType]
 // CHECK:STDOUT:     %J.ref: type = name_ref J, file.%J.decl [template = constants.%.7]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc145: <witness> = complete_type_witness %.5 [template = constants.%.6]
@@ -837,6 +847,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @FDifferentImplicitParamType {
 // CHECK:STDOUT:   impl_decl @impl.11 [template] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%FDifferentImplicitParamType [template = constants.%FDifferentImplicitParamType]
 // CHECK:STDOUT:     %J.ref: type = name_ref J, file.%J.decl [template = constants.%.7]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc158: <witness> = complete_type_witness %.5 [template = constants.%.6]
@@ -847,6 +858,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @FDifferentReturnType {
 // CHECK:STDOUT:   impl_decl @impl.12 [template] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%FDifferentReturnType [template = constants.%FDifferentReturnType]
 // CHECK:STDOUT:     %J.ref: type = name_ref J, file.%J.decl [template = constants.%.7]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc171: <witness> = complete_type_witness %.5 [template = constants.%.6]
@@ -857,6 +869,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @FDifferentParamName {
 // CHECK:STDOUT:   impl_decl @impl.13 [template] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%FDifferentParamName [template = constants.%FDifferentParamName]
 // CHECK:STDOUT:     %J.ref: type = name_ref J, file.%J.decl [template = constants.%.7]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc185: <witness> = complete_type_witness %.5 [template = constants.%.6]
@@ -867,6 +880,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @SelfNestedBadParam {
 // CHECK:STDOUT:   impl_decl @impl.14 [template] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%SelfNestedBadParam [template = constants.%SelfNestedBadParam]
 // CHECK:STDOUT:     %SelfNested.ref: type = name_ref SelfNested, file.%SelfNested.decl [template = constants.%.10]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc202: <witness> = complete_type_witness %.5 [template = constants.%.6]
@@ -877,6 +891,7 @@ class SelfNestedBadReturnType {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @SelfNestedBadReturnType {
 // CHECK:STDOUT:   impl_decl @impl.15 [template] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%SelfNestedBadReturnType [template = constants.%SelfNestedBadReturnType]
 // CHECK:STDOUT:     %SelfNested.ref: type = name_ref SelfNested, file.%SelfNested.decl [template = constants.%.10]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc214: <witness> = complete_type_witness %.5 [template = constants.%.6]

+ 1 - 1
toolchain/check/testdata/impl/fail_impl_bad_interface.carbon

@@ -103,7 +103,7 @@ impl i32 as false {}
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: i32 as <error> {
+// CHECK:STDOUT: impl @impl: %.loc21_6.2 as <error> {
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   witness = <error>
 // CHECK:STDOUT: }

+ 1 - 1
toolchain/check/testdata/impl/fail_redefinition.carbon

@@ -75,7 +75,7 @@ impl i32 as I {}
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: i32 as %.1 {
+// CHECK:STDOUT: impl @impl: %.loc13_6.2 as %I.ref.loc13 {
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   witness = <unexpected>.inst+18.loc13_15
 // CHECK:STDOUT: }

+ 1 - 1
toolchain/check/testdata/impl/fail_todo_impl_assoc_const.carbon

@@ -76,7 +76,7 @@ impl bool as I where .T = bool {}
 // CHECK:STDOUT:   witness = (%T)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: bool as %.1 {
+// CHECK:STDOUT: impl @impl: %.loc16_6.2 as %.loc16_16 {
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   witness = <error>
 // CHECK:STDOUT: }

+ 2 - 1
toolchain/check/testdata/impl/impl_as.carbon

@@ -76,7 +76,7 @@ class C {
 // CHECK:STDOUT:   witness = (%F.decl)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.1 {
+// CHECK:STDOUT: impl @impl: %Self.ref as %Simple.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {} {}
 // CHECK:STDOUT:   %.loc16: <witness> = interface_witness (%F.decl) [template = constants.%.5]
 // CHECK:STDOUT:
@@ -87,6 +87,7 @@ class C {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT:   impl_decl @impl [template] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%C [template = constants.%C]
 // CHECK:STDOUT:     %Simple.ref: type = name_ref Simple, file.%Simple.decl [template = constants.%.1]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc22: <witness> = complete_type_witness %.6 [template = constants.%.7]

+ 1 - 1
toolchain/check/testdata/impl/impl_forall.carbon

@@ -76,7 +76,7 @@ impl forall [T:! type] T as Simple {
 // CHECK:STDOUT: generic impl @impl(%T.loc15: type) {
 // CHECK:STDOUT:   %T.1: type = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   impl: %T as %.1 {
+// CHECK:STDOUT:   impl: %T.ref as %Simple.ref {
 // CHECK:STDOUT:     %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {} {}
 // CHECK:STDOUT:     %.loc15: <witness> = interface_witness (%F.decl) [template = constants.%.5]
 // CHECK:STDOUT:

+ 3 - 3
toolchain/check/testdata/impl/lookup/alias.carbon

@@ -93,7 +93,7 @@ fn G(c: C) {
 // CHECK:STDOUT:   witness = (%F.decl)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.1 {
+// CHECK:STDOUT: impl @impl: %C.ref as %HasF.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {} {}
 // CHECK:STDOUT:   %.loc19: <witness> = interface_witness (%F.decl) [template = constants.%.7]
 // CHECK:STDOUT:
@@ -127,11 +127,11 @@ fn G(c: C) {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %C.ref.loc24: type = name_ref C, file.%C.decl [template = constants.%C]
 // CHECK:STDOUT:   %G.ref.loc24: %.3 = name_ref G, @C.%G [template = constants.%.4]
-// CHECK:STDOUT:   %.loc24: %F.type.1 = interface_witness_access @impl.%.loc19, element0 [template = constants.%F.2]
+// CHECK:STDOUT:   %.loc24: %F.type.1 = interface_witness_access constants.%.7, element0 [template = constants.%F.2]
 // CHECK:STDOUT:   %F.call.loc24: init %.2 = call %.loc24()
 // CHECK:STDOUT:   %c.ref: %C = name_ref c, %c
 // CHECK:STDOUT:   %G.ref.loc25: %.3 = name_ref G, @C.%G [template = constants.%.4]
-// CHECK:STDOUT:   %.loc25: %F.type.1 = interface_witness_access @impl.%.loc19, element0 [template = constants.%F.2]
+// CHECK:STDOUT:   %.loc25: %F.type.1 = interface_witness_access constants.%.7, element0 [template = constants.%F.2]
 // CHECK:STDOUT:   %F.call.loc25: init %.2 = call %.loc25()
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }

+ 3 - 2
toolchain/check/testdata/impl/lookup/fail_todo_undefined_impl.carbon

@@ -99,9 +99,9 @@ impl C as I {
 // CHECK:STDOUT:   witness = (%F.decl)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.1: %C as %.1;
+// CHECK:STDOUT: impl @impl.1: %Self.ref as %I.ref;
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.2: %C as %.1 {
+// CHECK:STDOUT: impl @impl.2: %C.ref as %I.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.3 = fn_decl @F.3 [template = constants.%F.3] {} {}
 // CHECK:STDOUT:   %.loc27: <witness> = interface_witness (%F.decl) [template = constants.%.8]
 // CHECK:STDOUT:
@@ -112,6 +112,7 @@ impl C as I {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT:   impl_decl @impl.1 [template] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%C [template = constants.%C]
 // CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [template = constants.%.1]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc17: <witness> = complete_type_witness %.5 [template = constants.%.6]

+ 15 - 13
toolchain/check/testdata/impl/lookup/import.carbon

@@ -87,7 +87,7 @@ fn G(c: Impl.C) {
 // CHECK:STDOUT:   witness = (%F.decl)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.1 {
+// CHECK:STDOUT: impl @impl: %C.ref as %HasF.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {} {}
 // CHECK:STDOUT:   %.loc10: <witness> = interface_witness (%F.decl) [template = constants.%.7]
 // CHECK:STDOUT:
@@ -132,7 +132,7 @@ fn G(c: Impl.C) {
 // CHECK:STDOUT:   %F.type.1: type = fn_type @F.1 [template]
 // CHECK:STDOUT:   %F.1: %F.type.1 = struct_value () [template]
 // CHECK:STDOUT:   %.6: type = assoc_entity_type %.1, %F.type.1 [template]
-// CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, imports.%import_ref.8 [template]
+// CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, imports.%import_ref.10 [template]
 // CHECK:STDOUT:   %F.type.2: type = fn_type @F.2 [template]
 // CHECK:STDOUT:   %F.2: %F.type.2 = struct_value () [template]
 // CHECK:STDOUT:   %.8: <witness> = interface_witness (%F.2) [template]
@@ -150,18 +150,20 @@ fn G(c: Impl.C) {
 // CHECK:STDOUT:     import Core//prelude/types/bool
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Impl: <namespace> = namespace file.%Impl.import, [template] {
-// CHECK:STDOUT:     .C = %import_ref.6
-// CHECK:STDOUT:     .HasF = %import_ref.7
+// CHECK:STDOUT:     .C = %import_ref.8
+// CHECK:STDOUT:     .HasF = %import_ref.9
 // CHECK:STDOUT:     import Impl//default
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %import_ref.1 = import_ref Impl//default, inst+5, unloaded
 // CHECK:STDOUT:   %import_ref.2: %.6 = import_ref Impl//default, inst+12, loaded [template = constants.%.7]
 // CHECK:STDOUT:   %import_ref.3 = import_ref Impl//default, inst+7, unloaded
 // CHECK:STDOUT:   %import_ref.4 = import_ref Impl//default, inst+15, unloaded
-// CHECK:STDOUT:   %import_ref.5: <witness> = import_ref Impl//default, inst+25, loaded [template = constants.%.8]
-// CHECK:STDOUT:   %import_ref.6: type = import_ref Impl//default, inst+14, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.7: type = import_ref Impl//default, inst+3, loaded [template = constants.%.1]
-// CHECK:STDOUT:   %import_ref.8 = import_ref Impl//default, inst+7, unloaded
+// CHECK:STDOUT:   %import_ref.5: type = import_ref Impl//default, inst+19, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.6: type = import_ref Impl//default, inst+20, loaded [template = constants.%.1]
+// CHECK:STDOUT:   %import_ref.7: <witness> = import_ref Impl//default, inst+25, loaded [template = constants.%.8]
+// CHECK:STDOUT:   %import_ref.8: type = import_ref Impl//default, inst+14, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.9: type = import_ref Impl//default, inst+3, loaded [template = constants.%.1]
+// CHECK:STDOUT:   %import_ref.10 = import_ref Impl//default, inst+7, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -176,7 +178,7 @@ fn G(c: Impl.C) {
 // CHECK:STDOUT:     %c.patt: %C = binding_pattern c
 // CHECK:STDOUT:   } {
 // CHECK:STDOUT:     %Impl.ref.loc4: <namespace> = name_ref Impl, imports.%Impl [template = imports.%Impl]
-// CHECK:STDOUT:     %C.ref: type = name_ref C, imports.%import_ref.6 [template = constants.%C]
+// CHECK:STDOUT:     %C.ref: type = name_ref C, imports.%import_ref.8 [template = constants.%C]
 // CHECK:STDOUT:     %c.param: %C = param c, runtime_param0
 // CHECK:STDOUT:     %c: %C = bind_name c, %c.param
 // CHECK:STDOUT:   }
@@ -189,9 +191,9 @@ fn G(c: Impl.C) {
 // CHECK:STDOUT:   witness = (imports.%import_ref.3)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.1 {
+// CHECK:STDOUT: impl @impl: imports.%import_ref.5 as imports.%import_ref.6 {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   witness = imports.%import_ref.5
+// CHECK:STDOUT:   witness = imports.%import_ref.7
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
@@ -203,9 +205,9 @@ fn G(c: Impl.C) {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %c.ref: %C = name_ref c, %c
 // CHECK:STDOUT:   %Impl.ref.loc5: <namespace> = name_ref Impl, imports.%Impl [template = imports.%Impl]
-// CHECK:STDOUT:   %HasF.ref: type = name_ref HasF, imports.%import_ref.7 [template = constants.%.1]
+// CHECK:STDOUT:   %HasF.ref: type = name_ref HasF, imports.%import_ref.9 [template = constants.%.1]
 // CHECK:STDOUT:   %F.ref: %.6 = name_ref F, imports.%import_ref.2 [template = constants.%.7]
-// CHECK:STDOUT:   %.loc5: %F.type.1 = interface_witness_access imports.%import_ref.5, element0 [template = constants.%F.2]
+// CHECK:STDOUT:   %.loc5: %F.type.1 = interface_witness_access constants.%.8, element0 [template = constants.%F.2]
 // CHECK:STDOUT:   %F.call: init %.4 = call %.loc5()
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }

+ 3 - 2
toolchain/check/testdata/impl/lookup/instance_method.carbon

@@ -109,7 +109,7 @@ fn F(c: C) -> i32 {
 // CHECK:STDOUT:   witness = (%F.decl)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.1 {
+// CHECK:STDOUT: impl @impl: %Self.ref as %I.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {
 // CHECK:STDOUT:     %self.patt: %C = binding_pattern self
 // CHECK:STDOUT:   } {
@@ -130,6 +130,7 @@ fn F(c: C) -> i32 {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT:   impl_decl @impl [template] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%C [template = constants.%C]
 // CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [template = constants.%.1]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc21: <witness> = complete_type_witness %.6 [template = constants.%.7]
@@ -153,7 +154,7 @@ fn F(c: C) -> i32 {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %c.ref: %C = name_ref c, %c
 // CHECK:STDOUT:   %F.ref: %.3 = name_ref F, @I.%.loc14 [template = constants.%.4]
-// CHECK:STDOUT:   %.loc24_11.1: %F.type.1 = interface_witness_access @impl.%.loc18, element0 [template = constants.%F.2]
+// CHECK:STDOUT:   %.loc24_11.1: %F.type.1 = interface_witness_access constants.%.5, element0 [template = constants.%F.2]
 // CHECK:STDOUT:   %.loc24_11.2: <bound method> = bound_method %c.ref, %.loc24_11.1
 // CHECK:STDOUT:   %F.call: init i32 = call %.loc24_11.2(%c.ref)
 // CHECK:STDOUT:   %.loc24_15.1: i32 = value_of_initializer %F.call

+ 1 - 1
toolchain/check/testdata/impl/lookup/no_prelude/impl_forall.carbon

@@ -201,7 +201,7 @@ fn TestSpecific(a: A({})) -> {} {
 // CHECK:STDOUT:   %A.1: type = class_type @A, @A(%V.1) [symbolic = %A.1 (constants.%A.3)]
 // CHECK:STDOUT:   %.1: type = interface_type @I, @I(%V.1) [symbolic = %.1 (constants.%.8)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   impl: %A.3 as %.8 {
+// CHECK:STDOUT:   impl: %A.loc10 as %.loc10_33 {
 // CHECK:STDOUT:     %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {
 // CHECK:STDOUT:       %self.patt: @F.2.%A (%A.3) = binding_pattern self
 // CHECK:STDOUT:     } {

+ 15 - 13
toolchain/check/testdata/impl/lookup/no_prelude/import.carbon

@@ -72,7 +72,7 @@ fn G(c: Impl.C) {
 // CHECK:STDOUT:   witness = (%F.decl)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.1 {
+// CHECK:STDOUT: impl @impl: %C.ref as %HasF.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {} {}
 // CHECK:STDOUT:   %.loc10: <witness> = interface_witness (%F.decl) [template = constants.%.7]
 // CHECK:STDOUT:
@@ -117,7 +117,7 @@ fn G(c: Impl.C) {
 // CHECK:STDOUT:   %F.type.1: type = fn_type @F.1 [template]
 // CHECK:STDOUT:   %F.1: %F.type.1 = struct_value () [template]
 // CHECK:STDOUT:   %.6: type = assoc_entity_type %.1, %F.type.1 [template]
-// CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, imports.%import_ref.8 [template]
+// CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, imports.%import_ref.10 [template]
 // CHECK:STDOUT:   %F.type.2: type = fn_type @F.2 [template]
 // CHECK:STDOUT:   %F.2: %F.type.2 = struct_value () [template]
 // CHECK:STDOUT:   %.8: <witness> = interface_witness (%F.2) [template]
@@ -125,18 +125,20 @@ fn G(c: Impl.C) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %Impl: <namespace> = namespace file.%Impl.import, [template] {
-// CHECK:STDOUT:     .C = %import_ref.6
-// CHECK:STDOUT:     .HasF = %import_ref.7
+// CHECK:STDOUT:     .C = %import_ref.8
+// CHECK:STDOUT:     .HasF = %import_ref.9
 // CHECK:STDOUT:     import Impl//default
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %import_ref.1 = import_ref Impl//default, inst+3, unloaded
 // CHECK:STDOUT:   %import_ref.2: %.6 = import_ref Impl//default, inst+10, loaded [template = constants.%.7]
 // CHECK:STDOUT:   %import_ref.3 = import_ref Impl//default, inst+5, unloaded
 // CHECK:STDOUT:   %import_ref.4 = import_ref Impl//default, inst+13, unloaded
-// CHECK:STDOUT:   %import_ref.5: <witness> = import_ref Impl//default, inst+23, loaded [template = constants.%.8]
-// CHECK:STDOUT:   %import_ref.6: type = import_ref Impl//default, inst+12, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.7: type = import_ref Impl//default, inst+1, loaded [template = constants.%.1]
-// CHECK:STDOUT:   %import_ref.8 = import_ref Impl//default, inst+5, unloaded
+// CHECK:STDOUT:   %import_ref.5: type = import_ref Impl//default, inst+17, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.6: type = import_ref Impl//default, inst+18, loaded [template = constants.%.1]
+// CHECK:STDOUT:   %import_ref.7: <witness> = import_ref Impl//default, inst+23, loaded [template = constants.%.8]
+// CHECK:STDOUT:   %import_ref.8: type = import_ref Impl//default, inst+12, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.9: type = import_ref Impl//default, inst+1, loaded [template = constants.%.1]
+// CHECK:STDOUT:   %import_ref.10 = import_ref Impl//default, inst+5, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -149,7 +151,7 @@ fn G(c: Impl.C) {
 // CHECK:STDOUT:     %c.patt: %C = binding_pattern c
 // CHECK:STDOUT:   } {
 // CHECK:STDOUT:     %Impl.ref.loc4: <namespace> = name_ref Impl, imports.%Impl [template = imports.%Impl]
-// CHECK:STDOUT:     %C.ref: type = name_ref C, imports.%import_ref.6 [template = constants.%C]
+// CHECK:STDOUT:     %C.ref: type = name_ref C, imports.%import_ref.8 [template = constants.%C]
 // CHECK:STDOUT:     %c.param: %C = param c, runtime_param0
 // CHECK:STDOUT:     %c: %C = bind_name c, %c.param
 // CHECK:STDOUT:   }
@@ -162,9 +164,9 @@ fn G(c: Impl.C) {
 // CHECK:STDOUT:   witness = (imports.%import_ref.3)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.1 {
+// CHECK:STDOUT: impl @impl: imports.%import_ref.5 as imports.%import_ref.6 {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   witness = imports.%import_ref.5
+// CHECK:STDOUT:   witness = imports.%import_ref.7
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
@@ -176,9 +178,9 @@ fn G(c: Impl.C) {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %c.ref: %C = name_ref c, %c
 // CHECK:STDOUT:   %Impl.ref.loc5: <namespace> = name_ref Impl, imports.%Impl [template = imports.%Impl]
-// CHECK:STDOUT:   %HasF.ref: type = name_ref HasF, imports.%import_ref.7 [template = constants.%.1]
+// CHECK:STDOUT:   %HasF.ref: type = name_ref HasF, imports.%import_ref.9 [template = constants.%.1]
 // CHECK:STDOUT:   %F.ref: %.6 = name_ref F, imports.%import_ref.2 [template = constants.%.7]
-// CHECK:STDOUT:   %.loc5: %F.type.1 = interface_witness_access imports.%import_ref.5, element0 [template = constants.%F.2]
+// CHECK:STDOUT:   %.loc5: %F.type.1 = interface_witness_access constants.%.8, element0 [template = constants.%F.2]
 // CHECK:STDOUT:   %F.call: init %.4 = call %.loc5()
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }

+ 1 - 1
toolchain/check/testdata/impl/no_prelude/basic.carbon

@@ -60,7 +60,7 @@ impl C as Simple {
 // CHECK:STDOUT:   witness = (%F.decl)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.1 {
+// CHECK:STDOUT: impl @impl: %C.ref as %Simple.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {} {}
 // CHECK:STDOUT:   %.loc17: <witness> = interface_witness (%F.decl) [template = constants.%.7]
 // CHECK:STDOUT:

+ 81 - 0
toolchain/check/testdata/impl/no_prelude/fail_alias.carbon

@@ -0,0 +1,81 @@
+// 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/check/testdata/impl/no_prelude/fail_alias.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/impl/no_prelude/fail_alias.carbon
+
+interface I {}
+class C {}
+
+alias AI = I;
+alias AC = C;
+
+impl AC as AI {}
+
+// CHECK:STDERR: fail_alias.carbon:[[@LINE+6]]:1: error: redefinition of `impl AC as AI`
+// CHECK:STDERR: impl AC as AI {}
+// CHECK:STDERR: ^~~~~~~~~~~~~~~
+// CHECK:STDERR: fail_alias.carbon:[[@LINE-5]]:1: note: previous definition was here
+// CHECK:STDERR: impl AC as AI {}
+// CHECK:STDERR: ^~~~~~~~~~~~~~~
+impl AC as AI {}
+
+// CHECK:STDOUT: --- fail_alias.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %.1: type = interface_type @I [template]
+// CHECK:STDOUT:   %Self: %.1 = bind_symbolic_name Self, 0 [symbolic]
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.2: type = struct_type {} [template]
+// CHECK:STDOUT:   %.3: <witness> = complete_type_witness %.2 [template]
+// CHECK:STDOUT:   %.4: type = tuple_type () [template]
+// CHECK:STDOUT:   %.5: <witness> = interface_witness () [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .I = %I.decl
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .AI = %AI
+// CHECK:STDOUT:     .AC = %AC
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %I.decl: type = interface_decl @I [template = constants.%.1] {} {}
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {} {}
+// CHECK:STDOUT:   %I.ref: type = name_ref I, %I.decl [template = constants.%.1]
+// CHECK:STDOUT:   %AI: type = bind_alias AI, %I.decl [template = constants.%.1]
+// CHECK:STDOUT:   %C.ref: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %AC: type = bind_alias AC, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   impl_decl @impl [template] {} {
+// CHECK:STDOUT:     %AC.ref.loc17: type = name_ref AC, file.%AC [template = constants.%C]
+// CHECK:STDOUT:     %AI.ref.loc17: type = name_ref AI, file.%AI [template = constants.%.1]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   impl_decl @impl [template] {} {
+// CHECK:STDOUT:     %AC.ref.loc25: type = name_ref AC, file.%AC [template = constants.%C]
+// CHECK:STDOUT:     %AI.ref.loc25: type = name_ref AI, file.%AI [template = constants.%.1]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @I {
+// CHECK:STDOUT:   %Self: %.1 = bind_symbolic_name Self, 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   witness = ()
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: impl @impl: %AC.ref.loc17 as %AI.ref.loc17 {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   witness = <unexpected>.inst+18.loc17_15
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT:   %.loc12: <witness> = complete_type_witness %.2 [template = constants.%.3]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:

+ 1 - 1
toolchain/check/testdata/impl/no_prelude/fail_impl_bad_type.carbon

@@ -45,7 +45,7 @@ impl true as I {}
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: <error> as %.1 {
+// CHECK:STDOUT: impl @impl: <error> as %I.ref {
 // CHECK:STDOUT:   %.loc16_16: <witness> = interface_witness () [template = constants.%.4]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:

+ 11 - 11
toolchain/check/testdata/impl/no_prelude/generic_redeclaration.carbon

@@ -230,31 +230,31 @@ impl (C, C).0 as I {}
 // CHECK:STDOUT: generic impl @impl.1(%T.loc11: %.2) {
 // CHECK:STDOUT:   %T.1: %.2 = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T.1)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   impl: %T.1 as %.1;
+// CHECK:STDOUT:   impl: %.loc11_21.2 as %Interface.ref;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: generic impl @impl.2(%T.loc12: %.3) {
 // CHECK:STDOUT:   %T.1: %.3 = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T.2)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   impl: %T.2 as %.1;
+// CHECK:STDOUT:   impl: %.loc12_21.2 as %Interface.ref;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: generic impl @impl.3(%T.loc13: %.4) {
 // CHECK:STDOUT:   %T.1: %.4 = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T.3)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   impl: %T.3 as %.1;
+// CHECK:STDOUT:   impl: %.loc13_21.2 as %Interface.ref;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: generic impl @impl.4(%T.loc14: %.5) {
 // CHECK:STDOUT:   %T.1: %.5 = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T.4)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   impl: %T.4 as %.1;
+// CHECK:STDOUT:   impl: %.loc14_21.2 as %Interface.ref;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: generic impl @impl.5(%T.loc18: %.2) {
 // CHECK:STDOUT:   %T.1: %.2 = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T.1)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   impl: %T.1 as %.1 {
+// CHECK:STDOUT:   impl: %.loc18_21.2 as %Interface.ref {
 // CHECK:STDOUT:     %.loc18_36: <witness> = interface_witness () [template = constants.%.7]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   !members:
@@ -265,7 +265,7 @@ impl (C, C).0 as I {}
 // CHECK:STDOUT: generic impl @impl.6(%T.loc19: %.3) {
 // CHECK:STDOUT:   %T.1: %.3 = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T.2)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   impl: %T.2 as %.1 {
+// CHECK:STDOUT:   impl: %.loc19_21.2 as %Interface.ref {
 // CHECK:STDOUT:     %.loc19_36: <witness> = interface_witness () [template = constants.%.7]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   !members:
@@ -276,7 +276,7 @@ impl (C, C).0 as I {}
 // CHECK:STDOUT: generic impl @impl.7(%T.loc20: %.4) {
 // CHECK:STDOUT:   %T.1: %.4 = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T.3)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   impl: %T.3 as %.1 {
+// CHECK:STDOUT:   impl: %.loc20_21.2 as %Interface.ref {
 // CHECK:STDOUT:     %.loc20_36: <witness> = interface_witness () [template = constants.%.7]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   !members:
@@ -287,7 +287,7 @@ impl (C, C).0 as I {}
 // CHECK:STDOUT: generic impl @impl.8(%T.loc21: %.5) {
 // CHECK:STDOUT:   %T.1: %.5 = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T.4)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   impl: %T.4 as %.1 {
+// CHECK:STDOUT:   impl: %.loc21_21.2 as %Interface.ref {
 // CHECK:STDOUT:     %.loc21_36: <witness> = interface_witness () [template = constants.%.7]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   !members:
@@ -389,7 +389,7 @@ impl (C, C).0 as I {}
 // CHECK:STDOUT: generic impl @impl(%T.loc7: %.1) {
 // CHECK:STDOUT:   %T.1: %.1 = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   impl: %T as %.2 {
+// CHECK:STDOUT:   impl: %.loc7_21.2 as %J.ref.loc7 {
 // CHECK:STDOUT:   !members:
 // CHECK:STDOUT:     witness = <unexpected>.inst+21.loc7_28
 // CHECK:STDOUT:   }
@@ -444,14 +444,14 @@ impl (C, C).0 as I {}
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.1: %C as %.1 {
+// CHECK:STDOUT: impl @impl.1: %C.ref as %I.ref {
 // CHECK:STDOUT:   %.loc13: <witness> = interface_witness () [template = constants.%.3]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   witness = %.loc13
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.2: %C as %.1 {
+// CHECK:STDOUT: impl @impl.2: %.loc14_12 as %I.ref {
 // CHECK:STDOUT:   %.loc14_20: <witness> = interface_witness () [template = constants.%.3]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:

+ 18 - 18
toolchain/check/testdata/impl/no_prelude/import_generic.carbon

@@ -109,7 +109,7 @@ impl forall [T:! type] C as I(T*) {}
 // CHECK:STDOUT:   %T.1: type = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T)]
 // CHECK:STDOUT:   %.1: type = interface_type @I, @I(%T.1) [symbolic = %.1 (constants.%.4)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   impl: %C as %.4;
+// CHECK:STDOUT:   impl: %C.ref as %.loc7;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: generic impl @impl.2(%T.loc8: type) {
@@ -117,7 +117,7 @@ impl forall [T:! type] C as I(T*) {}
 // CHECK:STDOUT:   %.1: type = ptr_type @impl.2.%T.1 (%T) [symbolic = %.1 (constants.%.5)]
 // CHECK:STDOUT:   %.2: type = interface_type @I, @I(%.1) [symbolic = %.2 (constants.%.6)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   impl: %C as %.6 {
+// CHECK:STDOUT:   impl: %C.ref as %.loc8_30 {
 // CHECK:STDOUT:     %.loc8_35: <witness> = interface_witness () [template = constants.%.7]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   !members:
@@ -190,7 +190,11 @@ impl forall [T:! type] C as I(T*) {}
 // CHECK:STDOUT:   %import_ref.2: %I.type = import_ref Main//import_generic, inst+10, loaded [template = constants.%I]
 // CHECK:STDOUT:   %import_ref.3 = import_ref Main//import_generic, inst+16, unloaded
 // CHECK:STDOUT:   %import_ref.4 = import_ref Main//import_generic, inst+2, unloaded
-// CHECK:STDOUT:   %import_ref.5 = import_ref Main//import_generic, inst+44, unloaded
+// CHECK:STDOUT:   %import_ref.5: type = import_ref Main//import_generic, inst+23, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.6: type = import_ref Main//import_generic, inst+26, loaded [symbolic = @impl.1.%.1 (constants.%.2)]
+// CHECK:STDOUT:   %import_ref.7: type = import_ref Main//import_generic, inst+33, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.8: type = import_ref Main//import_generic, inst+38, loaded [symbolic = @impl.2.%.2 (constants.%.6)]
+// CHECK:STDOUT:   %import_ref.9 = import_ref Main//import_generic, inst+44, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -228,7 +232,7 @@ impl forall [T:! type] C as I(T*) {}
 // CHECK:STDOUT:   %T.1: type = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T)]
 // CHECK:STDOUT:   %.1: type = interface_type @I, @I(%T.1) [symbolic = %.1 (constants.%.2)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   impl: %C as %.2 {
+// CHECK:STDOUT:   impl: imports.%import_ref.5 as imports.%import_ref.6 {
 // CHECK:STDOUT:     %.loc4_34: <witness> = interface_witness () [template = constants.%.7]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   !members:
@@ -241,9 +245,9 @@ impl forall [T:! type] C as I(T*) {}
 // CHECK:STDOUT:   %.1: type = ptr_type @impl.2.%T (%T) [symbolic = %.1 (constants.%.5)]
 // CHECK:STDOUT:   %.2: type = interface_type @I, @I(%.1) [symbolic = %.2 (constants.%.6)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   impl: %C as %.6 {
+// CHECK:STDOUT:   impl: imports.%import_ref.7 as imports.%import_ref.8 {
 // CHECK:STDOUT:   !members:
-// CHECK:STDOUT:     witness = imports.%import_ref.5
+// CHECK:STDOUT:     witness = imports.%import_ref.9
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -275,10 +279,6 @@ impl forall [T:! type] C as I(T*) {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @I(constants.%.5) {
 // CHECK:STDOUT:   %T => constants.%.5
-// CHECK:STDOUT:
-// CHECK:STDOUT: !definition:
-// CHECK:STDOUT:   %.1 => constants.%.6
-// CHECK:STDOUT:   %Self => constants.%Self.2
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @I(@impl.2.%.1) {
@@ -313,7 +313,11 @@ impl forall [T:! type] C as I(T*) {}
 // CHECK:STDOUT:   %import_ref.2: %I.type = import_ref Main//import_generic, inst+10, loaded [template = constants.%I]
 // CHECK:STDOUT:   %import_ref.3 = import_ref Main//import_generic, inst+16, unloaded
 // CHECK:STDOUT:   %import_ref.4 = import_ref Main//import_generic, inst+2, unloaded
-// CHECK:STDOUT:   %import_ref.5 = import_ref Main//import_generic, inst+44, unloaded
+// CHECK:STDOUT:   %import_ref.5: type = import_ref Main//import_generic, inst+23, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.6: type = import_ref Main//import_generic, inst+26, loaded [symbolic = @impl.1.%.1 (constants.%.2)]
+// CHECK:STDOUT:   %import_ref.7: type = import_ref Main//import_generic, inst+33, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.8: type = import_ref Main//import_generic, inst+38, loaded [symbolic = @impl.2.%.2 (constants.%.6)]
+// CHECK:STDOUT:   %import_ref.9 = import_ref Main//import_generic, inst+44, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -352,7 +356,7 @@ impl forall [T:! type] C as I(T*) {}
 // CHECK:STDOUT:   %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)]
 // CHECK:STDOUT:   %.1: type = interface_type @I, @I(%T) [symbolic = %.1 (constants.%.2)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   impl: %C as %.2;
+// CHECK:STDOUT:   impl: imports.%import_ref.5 as imports.%import_ref.6;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: generic impl @impl.2(constants.%T: type) {
@@ -360,9 +364,9 @@ impl forall [T:! type] C as I(T*) {}
 // CHECK:STDOUT:   %.1: type = ptr_type @impl.2.%T.1 (%T) [symbolic = %.1 (constants.%.5)]
 // CHECK:STDOUT:   %.2: type = interface_type @I, @I(%.1) [symbolic = %.2 (constants.%.6)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   impl: %C as %.6 {
+// CHECK:STDOUT:   impl: imports.%import_ref.7 as imports.%import_ref.8 {
 // CHECK:STDOUT:   !members:
-// CHECK:STDOUT:     witness = imports.%import_ref.5
+// CHECK:STDOUT:     witness = imports.%import_ref.9
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -390,10 +394,6 @@ impl forall [T:! type] C as I(T*) {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @I(constants.%.5) {
 // CHECK:STDOUT:   %T => constants.%.5
-// CHECK:STDOUT:
-// CHECK:STDOUT: !definition:
-// CHECK:STDOUT:   %.1 => constants.%.6
-// CHECK:STDOUT:   %Self => constants.%Self.2
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @I(@impl.2.%.1) {

+ 2 - 2
toolchain/check/testdata/impl/no_prelude/import_self.carbon

@@ -150,7 +150,7 @@ fn F(x: (), y: ()) -> () {
 // CHECK:STDOUT:   witness = (imports.%import_ref.4)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %.1 as %.2 {
+// CHECK:STDOUT: impl @impl: %.loc6_7.2 as %Add.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.1 = fn_decl @Op.1 [template = constants.%Op.1] {
 // CHECK:STDOUT:     %self.patt: %.1 = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %.1 = binding_pattern other
@@ -190,7 +190,7 @@ fn F(x: (), y: ()) -> () {
 // CHECK:STDOUT:   %x.ref: %.1 = name_ref x, %x
 // CHECK:STDOUT:   %Add.ref: type = name_ref Add, imports.%import_ref.1 [template = constants.%.2]
 // CHECK:STDOUT:   %Op.ref: %.4 = name_ref Op, imports.%import_ref.3 [template = constants.%.5]
-// CHECK:STDOUT:   %.loc11_11.1: %Op.type.2 = interface_witness_access @impl.%.loc6_16, element0 [template = constants.%Op.1]
+// CHECK:STDOUT:   %.loc11_11.1: %Op.type.2 = interface_witness_access constants.%.3, element0 [template = constants.%Op.1]
 // CHECK:STDOUT:   %.loc11_11.2: <bound method> = bound_method %x.ref, %.loc11_11.1
 // CHECK:STDOUT:   %y.ref: %.1 = name_ref y, %y
 // CHECK:STDOUT:   %Op.call: init %.1 = call %.loc11_11.2(%x.ref, %y.ref)

+ 61 - 53
toolchain/check/testdata/impl/no_prelude/interface_args.carbon

@@ -164,7 +164,7 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %A as %.7 {
+// CHECK:STDOUT: impl @impl: %A.ref as %.loc12_17 {
 // CHECK:STDOUT:   %Op.decl: %Op.type.2 = fn_decl @Op.2 [template = constants.%Op.2] {} {}
 // CHECK:STDOUT:   %.loc12_21: <witness> = interface_witness (%Op.decl) [template = constants.%.10]
 // CHECK:STDOUT:
@@ -212,7 +212,7 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %.loc16_23: type = interface_type @Action, @Action(constants.%B) [template = constants.%.7]
 // CHECK:STDOUT:   %.loc16_26: %.8 = specific_constant @Action.%.loc5, @Action(constants.%B) [template = constants.%.9]
 // CHECK:STDOUT:   %Op.ref: %.8 = name_ref Op, %.loc16_26 [template = constants.%.9]
-// CHECK:STDOUT:   %.loc16_15: %Op.type.3 = interface_witness_access @impl.%.loc12_21, element0 [template = constants.%Op.2]
+// CHECK:STDOUT:   %.loc16_15: %Op.type.3 = interface_witness_access constants.%.10, element0 [template = constants.%Op.2]
 // CHECK:STDOUT:   %Op.call: init %.1 = call %.loc16_15()
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
@@ -259,15 +259,15 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %Op.type.1: type = fn_type @Op.1, @Action(%T) [symbolic]
 // CHECK:STDOUT:   %Op.1: %Op.type.1 = struct_value () [symbolic]
 // CHECK:STDOUT:   %.6: type = assoc_entity_type %.4, %Op.type.1 [symbolic]
-// CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, imports.%import_ref.13 [symbolic]
+// CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, imports.%import_ref.15 [symbolic]
 // CHECK:STDOUT:   %Op.type.2: type = fn_type @Op.1, @Action(%B) [template]
 // CHECK:STDOUT:   %Op.2: %Op.type.2 = struct_value () [template]
 // CHECK:STDOUT:   %.8: type = assoc_entity_type %.5, %Op.type.2 [template]
-// CHECK:STDOUT:   %.9: %.8 = assoc_entity element0, imports.%import_ref.14 [template]
+// CHECK:STDOUT:   %.9: %.8 = assoc_entity element0, imports.%import_ref.16 [template]
 // CHECK:STDOUT:   %G.type: type = fn_type @G [template]
 // CHECK:STDOUT:   %G: %G.type = struct_value () [template]
 // CHECK:STDOUT:   %.10: type = ptr_type %.1 [template]
-// CHECK:STDOUT:   %.11: %.6 = assoc_entity element0, imports.%import_ref.15 [symbolic]
+// CHECK:STDOUT:   %.11: %.6 = assoc_entity element0, imports.%import_ref.17 [symbolic]
 // CHECK:STDOUT:   %Op.type.3: type = fn_type @Op.2 [template]
 // CHECK:STDOUT:   %Op.3: %Op.type.3 = struct_value () [template]
 // CHECK:STDOUT:   %.12: <witness> = interface_witness (%Op.3) [template]
@@ -284,11 +284,13 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %import_ref.8: @Action.%.2 (%.6) = import_ref Main//action, inst+17, loaded [symbolic = @Action.%.3 (constants.%.11)]
 // CHECK:STDOUT:   %import_ref.9 = import_ref Main//action, inst+13, unloaded
 // CHECK:STDOUT:   %import_ref.10 = import_ref Main//action, inst+26, unloaded
-// CHECK:STDOUT:   %import_ref.11: <witness> = import_ref Main//action, inst+49, loaded [template = constants.%.12]
-// CHECK:STDOUT:   %import_ref.12 = import_ref Main//action, inst+42, unloaded
-// CHECK:STDOUT:   %import_ref.13 = import_ref Main//action, inst+13, unloaded
-// CHECK:STDOUT:   %import_ref.14 = import_ref Main//action, inst+13, unloaded
+// CHECK:STDOUT:   %import_ref.11: type = import_ref Main//action, inst+36, loaded [template = constants.%A]
+// CHECK:STDOUT:   %import_ref.12: type = import_ref Main//action, inst+39, loaded [template = constants.%.5]
+// CHECK:STDOUT:   %import_ref.13: <witness> = import_ref Main//action, inst+49, loaded [template = constants.%.12]
+// CHECK:STDOUT:   %import_ref.14 = import_ref Main//action, inst+42, unloaded
 // CHECK:STDOUT:   %import_ref.15 = import_ref Main//action, inst+13, unloaded
+// CHECK:STDOUT:   %import_ref.16 = import_ref Main//action, inst+13, unloaded
+// CHECK:STDOUT:   %import_ref.17 = import_ref Main//action, inst+13, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -320,7 +322,7 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %Op.type: type = fn_type @Op.1, @Action(%T) [symbolic = %Op.type (constants.%Op.type.1)]
 // CHECK:STDOUT:   %Op: @Action.%Op.type (%Op.type.1) = struct_value () [symbolic = %Op (constants.%Op.1)]
 // CHECK:STDOUT:   %.2: type = assoc_entity_type @Action.%.1 (%.4), @Action.%Op.type (%Op.type.1) [symbolic = %.2 (constants.%.6)]
-// CHECK:STDOUT:   %.3: @Action.%.2 (%.6) = assoc_entity element0, imports.%import_ref.13 [symbolic = %.3 (constants.%.7)]
+// CHECK:STDOUT:   %.3: @Action.%.2 (%.6) = assoc_entity element0, imports.%import_ref.15 [symbolic = %.3 (constants.%.7)]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   interface {
 // CHECK:STDOUT:   !members:
@@ -330,10 +332,10 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %A as %.5 {
+// CHECK:STDOUT: impl @impl: imports.%import_ref.11 as imports.%import_ref.12 {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Op = imports.%import_ref.12
-// CHECK:STDOUT:   witness = imports.%import_ref.11
+// CHECK:STDOUT:   .Op = imports.%import_ref.14
+// CHECK:STDOUT:   witness = imports.%import_ref.13
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @B {
@@ -359,7 +361,7 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %.loc4_23: type = interface_type @Action, @Action(constants.%B) [template = constants.%.5]
 // CHECK:STDOUT:   %.loc4_26: %.8 = specific_constant imports.%import_ref.8, @Action(constants.%B) [template = constants.%.9]
 // CHECK:STDOUT:   %Op.ref: %.8 = name_ref Op, %.loc4_26 [template = constants.%.9]
-// CHECK:STDOUT:   %.loc4_15: %Op.type.2 = interface_witness_access imports.%import_ref.11, element0 [template = constants.%Op.3]
+// CHECK:STDOUT:   %.loc4_15: %Op.type.2 = interface_witness_access constants.%.12, element0 [template = constants.%Op.3]
 // CHECK:STDOUT:   %Op.call: init %.3 = call %.loc4_15()
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
@@ -406,11 +408,11 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %Op.type.1: type = fn_type @Op, @Action(%T) [symbolic]
 // CHECK:STDOUT:   %Op.1: %Op.type.1 = struct_value () [symbolic]
 // CHECK:STDOUT:   %.6: type = assoc_entity_type %.4, %Op.type.1 [symbolic]
-// CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, imports.%import_ref.13 [symbolic]
+// CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, imports.%import_ref.15 [symbolic]
 // CHECK:STDOUT:   %Op.type.2: type = fn_type @Op, @Action(%B) [template]
 // CHECK:STDOUT:   %Op.2: %Op.type.2 = struct_value () [template]
 // CHECK:STDOUT:   %.8: type = assoc_entity_type %.5, %Op.type.2 [template]
-// CHECK:STDOUT:   %.9: %.8 = assoc_entity element0, imports.%import_ref.14 [template]
+// CHECK:STDOUT:   %.9: %.8 = assoc_entity element0, imports.%import_ref.16 [template]
 // CHECK:STDOUT:   %G.type: type = fn_type @G [template]
 // CHECK:STDOUT:   %G: %G.type = struct_value () [template]
 // CHECK:STDOUT:   %.10: type = ptr_type %.1 [template]
@@ -419,8 +421,8 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %Op.type.3: type = fn_type @Op, @Action(%C) [template]
 // CHECK:STDOUT:   %Op.3: %Op.type.3 = struct_value () [template]
 // CHECK:STDOUT:   %.12: type = assoc_entity_type %.11, %Op.type.3 [template]
-// CHECK:STDOUT:   %.13: %.12 = assoc_entity element0, imports.%import_ref.13 [template]
-// CHECK:STDOUT:   %.14: %.6 = assoc_entity element0, imports.%import_ref.16 [symbolic]
+// CHECK:STDOUT:   %.13: %.12 = assoc_entity element0, imports.%import_ref.15 [template]
+// CHECK:STDOUT:   %.14: %.6 = assoc_entity element0, imports.%import_ref.18 [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -434,12 +436,14 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %import_ref.8: @Action.%.2 (%.6) = import_ref Main//action, inst+17, loaded [symbolic = @Action.%.3 (constants.%.14)]
 // CHECK:STDOUT:   %import_ref.9 = import_ref Main//action, inst+13, unloaded
 // CHECK:STDOUT:   %import_ref.10 = import_ref Main//action, inst+26, unloaded
-// CHECK:STDOUT:   %import_ref.11 = import_ref Main//action, inst+49, unloaded
-// CHECK:STDOUT:   %import_ref.12 = import_ref Main//action, inst+42, unloaded
-// CHECK:STDOUT:   %import_ref.13 = import_ref Main//action, inst+13, unloaded
-// CHECK:STDOUT:   %import_ref.14 = import_ref Main//action, inst+13, unloaded
-// CHECK:STDOUT:   %import_ref.15 = import_ref Main//action, inst+34, unloaded
+// CHECK:STDOUT:   %import_ref.11: type = import_ref Main//action, inst+36, loaded [template = constants.%A]
+// CHECK:STDOUT:   %import_ref.12: type = import_ref Main//action, inst+39, loaded [template = constants.%.5]
+// CHECK:STDOUT:   %import_ref.13 = import_ref Main//action, inst+49, unloaded
+// CHECK:STDOUT:   %import_ref.14 = import_ref Main//action, inst+42, unloaded
+// CHECK:STDOUT:   %import_ref.15 = import_ref Main//action, inst+13, unloaded
 // CHECK:STDOUT:   %import_ref.16 = import_ref Main//action, inst+13, unloaded
+// CHECK:STDOUT:   %import_ref.17 = import_ref Main//action, inst+34, unloaded
+// CHECK:STDOUT:   %import_ref.18 = import_ref Main//action, inst+13, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -471,7 +475,7 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %Op.type: type = fn_type @Op, @Action(%T) [symbolic = %Op.type (constants.%Op.type.1)]
 // CHECK:STDOUT:   %Op: @Action.%Op.type (%Op.type.1) = struct_value () [symbolic = %Op (constants.%Op.1)]
 // CHECK:STDOUT:   %.2: type = assoc_entity_type @Action.%.1 (%.4), @Action.%Op.type (%Op.type.1) [symbolic = %.2 (constants.%.6)]
-// CHECK:STDOUT:   %.3: @Action.%.2 (%.6) = assoc_entity element0, imports.%import_ref.13 [symbolic = %.3 (constants.%.7)]
+// CHECK:STDOUT:   %.3: @Action.%.2 (%.6) = assoc_entity element0, imports.%import_ref.15 [symbolic = %.3 (constants.%.7)]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   interface {
 // CHECK:STDOUT:   !members:
@@ -481,10 +485,10 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %A as %.5 {
+// CHECK:STDOUT: impl @impl: imports.%import_ref.11 as imports.%import_ref.12 {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Op = imports.%import_ref.12
-// CHECK:STDOUT:   witness = imports.%import_ref.11
+// CHECK:STDOUT:   .Op = imports.%import_ref.14
+// CHECK:STDOUT:   witness = imports.%import_ref.13
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @B {
@@ -499,7 +503,7 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = imports.%import_ref.15
+// CHECK:STDOUT:   .Self = imports.%import_ref.17
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: generic fn @Op(constants.%T: type, constants.%Self.1: @Action.%.1 (%.4)) {
@@ -627,7 +631,7 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %A as %.7 {
+// CHECK:STDOUT: impl @impl: %A.ref as %.loc11_18 {
 // CHECK:STDOUT:   %Make.decl: %Make.type.2 = fn_decl @Make.2 [template = constants.%Make.2] {} {
 // CHECK:STDOUT:     %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
 // CHECK:STDOUT:     %return: ref %B = var <return slot>
@@ -707,15 +711,15 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %Make.type.1: type = fn_type @Make.1, @Factory(%T) [symbolic]
 // CHECK:STDOUT:   %Make.1: %Make.type.1 = struct_value () [symbolic]
 // CHECK:STDOUT:   %.6: type = assoc_entity_type %.4, %Make.type.1 [symbolic]
-// CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, imports.%import_ref.11 [symbolic]
+// CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, imports.%import_ref.13 [symbolic]
 // CHECK:STDOUT:   %Make.type.2: type = fn_type @Make.1, @Factory(%B) [template]
 // CHECK:STDOUT:   %Make.2: %Make.type.2 = struct_value () [template]
 // CHECK:STDOUT:   %.8: type = assoc_entity_type %.5, %Make.type.2 [template]
-// CHECK:STDOUT:   %.9: %.8 = assoc_entity element0, imports.%import_ref.12 [template]
+// CHECK:STDOUT:   %.9: %.8 = assoc_entity element0, imports.%import_ref.14 [template]
 // CHECK:STDOUT:   %MakeB.type: type = fn_type @MakeB [template]
 // CHECK:STDOUT:   %MakeB: %MakeB.type = struct_value () [template]
 // CHECK:STDOUT:   %.10: type = ptr_type %.1 [template]
-// CHECK:STDOUT:   %.11: %.6 = assoc_entity element0, imports.%import_ref.13 [symbolic]
+// CHECK:STDOUT:   %.11: %.6 = assoc_entity element0, imports.%import_ref.15 [symbolic]
 // CHECK:STDOUT:   %Make.type.3: type = fn_type @Make.2 [template]
 // CHECK:STDOUT:   %Make.3: %Make.type.3 = struct_value () [template]
 // CHECK:STDOUT:   %.12: <witness> = interface_witness (%Make.3) [template]
@@ -730,11 +734,13 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %import_ref.6: @Factory.%.2 (%.6) = import_ref Main//factory, inst+20, loaded [symbolic = @Factory.%.3 (constants.%.11)]
 // CHECK:STDOUT:   %import_ref.7 = import_ref Main//factory, inst+15, unloaded
 // CHECK:STDOUT:   %import_ref.8 = import_ref Main//factory, inst+29, unloaded
-// CHECK:STDOUT:   %import_ref.9: <witness> = import_ref Main//factory, inst+51, loaded [template = constants.%.12]
-// CHECK:STDOUT:   %import_ref.10 = import_ref Main//factory, inst+44, unloaded
-// CHECK:STDOUT:   %import_ref.11 = import_ref Main//factory, inst+15, unloaded
-// CHECK:STDOUT:   %import_ref.12 = import_ref Main//factory, inst+15, unloaded
+// CHECK:STDOUT:   %import_ref.9: type = import_ref Main//factory, inst+36, loaded [template = constants.%A]
+// CHECK:STDOUT:   %import_ref.10: type = import_ref Main//factory, inst+39, loaded [template = constants.%.5]
+// CHECK:STDOUT:   %import_ref.11: <witness> = import_ref Main//factory, inst+51, loaded [template = constants.%.12]
+// CHECK:STDOUT:   %import_ref.12 = import_ref Main//factory, inst+44, unloaded
 // CHECK:STDOUT:   %import_ref.13 = import_ref Main//factory, inst+15, unloaded
+// CHECK:STDOUT:   %import_ref.14 = import_ref Main//factory, inst+15, unloaded
+// CHECK:STDOUT:   %import_ref.15 = import_ref Main//factory, inst+15, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -766,7 +772,7 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %Make.type: type = fn_type @Make.1, @Factory(%T) [symbolic = %Make.type (constants.%Make.type.1)]
 // CHECK:STDOUT:   %Make: @Factory.%Make.type (%Make.type.1) = struct_value () [symbolic = %Make (constants.%Make.1)]
 // CHECK:STDOUT:   %.2: type = assoc_entity_type @Factory.%.1 (%.4), @Factory.%Make.type (%Make.type.1) [symbolic = %.2 (constants.%.6)]
-// CHECK:STDOUT:   %.3: @Factory.%.2 (%.6) = assoc_entity element0, imports.%import_ref.11 [symbolic = %.3 (constants.%.7)]
+// CHECK:STDOUT:   %.3: @Factory.%.2 (%.6) = assoc_entity element0, imports.%import_ref.13 [symbolic = %.3 (constants.%.7)]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   interface {
 // CHECK:STDOUT:   !members:
@@ -776,10 +782,10 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %A as %.5 {
+// CHECK:STDOUT: impl @impl: imports.%import_ref.9 as imports.%import_ref.10 {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Make = imports.%import_ref.10
-// CHECK:STDOUT:   witness = imports.%import_ref.9
+// CHECK:STDOUT:   .Make = imports.%import_ref.12
+// CHECK:STDOUT:   witness = imports.%import_ref.11
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @B {
@@ -806,7 +812,7 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %.loc5_20: type = interface_type @Factory, @Factory(constants.%B) [template = constants.%.5]
 // CHECK:STDOUT:   %.loc5_23: %.8 = specific_constant imports.%import_ref.6, @Factory(constants.%B) [template = constants.%.9]
 // CHECK:STDOUT:   %Make.ref: %.8 = name_ref Make, %.loc5_23 [template = constants.%.9]
-// CHECK:STDOUT:   %.loc5_11: %Make.type.2 = interface_witness_access imports.%import_ref.9, element0 [template = constants.%Make.3]
+// CHECK:STDOUT:   %.loc5_11: %Make.type.2 = interface_witness_access constants.%.12, element0 [template = constants.%Make.3]
 // CHECK:STDOUT:   %.loc4: ref %B = splice_block %return {}
 // CHECK:STDOUT:   %Make.call: init %B = call %.loc5_11() to %.loc4
 // CHECK:STDOUT:   return %Make.call to %return
@@ -856,11 +862,11 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %Make.type.1: type = fn_type @Make, @Factory(%T) [symbolic]
 // CHECK:STDOUT:   %Make.1: %Make.type.1 = struct_value () [symbolic]
 // CHECK:STDOUT:   %.6: type = assoc_entity_type %.4, %Make.type.1 [symbolic]
-// CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, imports.%import_ref.11 [symbolic]
+// CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, imports.%import_ref.13 [symbolic]
 // CHECK:STDOUT:   %Make.type.2: type = fn_type @Make, @Factory(%B) [template]
 // CHECK:STDOUT:   %Make.2: %Make.type.2 = struct_value () [template]
 // CHECK:STDOUT:   %.8: type = assoc_entity_type %.5, %Make.type.2 [template]
-// CHECK:STDOUT:   %.9: %.8 = assoc_entity element0, imports.%import_ref.12 [template]
+// CHECK:STDOUT:   %.9: %.8 = assoc_entity element0, imports.%import_ref.14 [template]
 // CHECK:STDOUT:   %C: type = class_type @C [template]
 // CHECK:STDOUT:   %MakeC.type: type = fn_type @MakeC [template]
 // CHECK:STDOUT:   %MakeC: %MakeC.type = struct_value () [template]
@@ -869,8 +875,8 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %Make.type.3: type = fn_type @Make, @Factory(%C) [template]
 // CHECK:STDOUT:   %Make.3: %Make.type.3 = struct_value () [template]
 // CHECK:STDOUT:   %.12: type = assoc_entity_type %.11, %Make.type.3 [template]
-// CHECK:STDOUT:   %.13: %.12 = assoc_entity element0, imports.%import_ref.11 [template]
-// CHECK:STDOUT:   %.14: %.6 = assoc_entity element0, imports.%import_ref.13 [symbolic]
+// CHECK:STDOUT:   %.13: %.12 = assoc_entity element0, imports.%import_ref.13 [template]
+// CHECK:STDOUT:   %.14: %.6 = assoc_entity element0, imports.%import_ref.15 [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -882,11 +888,13 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %import_ref.6: @Factory.%.2 (%.6) = import_ref Main//factory, inst+20, loaded [symbolic = @Factory.%.3 (constants.%.14)]
 // CHECK:STDOUT:   %import_ref.7 = import_ref Main//factory, inst+15, unloaded
 // CHECK:STDOUT:   %import_ref.8 = import_ref Main//factory, inst+29, unloaded
-// CHECK:STDOUT:   %import_ref.9 = import_ref Main//factory, inst+51, unloaded
-// CHECK:STDOUT:   %import_ref.10 = import_ref Main//factory, inst+44, unloaded
-// CHECK:STDOUT:   %import_ref.11 = import_ref Main//factory, inst+15, unloaded
-// CHECK:STDOUT:   %import_ref.12 = import_ref Main//factory, inst+15, unloaded
+// CHECK:STDOUT:   %import_ref.9: type = import_ref Main//factory, inst+36, loaded [template = constants.%A]
+// CHECK:STDOUT:   %import_ref.10: type = import_ref Main//factory, inst+39, loaded [template = constants.%.5]
+// CHECK:STDOUT:   %import_ref.11 = import_ref Main//factory, inst+51, unloaded
+// CHECK:STDOUT:   %import_ref.12 = import_ref Main//factory, inst+44, unloaded
 // CHECK:STDOUT:   %import_ref.13 = import_ref Main//factory, inst+15, unloaded
+// CHECK:STDOUT:   %import_ref.14 = import_ref Main//factory, inst+15, unloaded
+// CHECK:STDOUT:   %import_ref.15 = import_ref Main//factory, inst+15, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -920,7 +928,7 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %Make.type: type = fn_type @Make, @Factory(%T) [symbolic = %Make.type (constants.%Make.type.1)]
 // CHECK:STDOUT:   %Make: @Factory.%Make.type (%Make.type.1) = struct_value () [symbolic = %Make (constants.%Make.1)]
 // CHECK:STDOUT:   %.2: type = assoc_entity_type @Factory.%.1 (%.4), @Factory.%Make.type (%Make.type.1) [symbolic = %.2 (constants.%.6)]
-// CHECK:STDOUT:   %.3: @Factory.%.2 (%.6) = assoc_entity element0, imports.%import_ref.11 [symbolic = %.3 (constants.%.7)]
+// CHECK:STDOUT:   %.3: @Factory.%.2 (%.6) = assoc_entity element0, imports.%import_ref.13 [symbolic = %.3 (constants.%.7)]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   interface {
 // CHECK:STDOUT:   !members:
@@ -930,10 +938,10 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %A as %.5 {
+// CHECK:STDOUT: impl @impl: imports.%import_ref.9 as imports.%import_ref.10 {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Make = imports.%import_ref.10
-// CHECK:STDOUT:   witness = imports.%import_ref.9
+// CHECK:STDOUT:   .Make = imports.%import_ref.12
+// CHECK:STDOUT:   witness = imports.%import_ref.11
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @B {

+ 16 - 8
toolchain/check/testdata/impl/no_prelude/no_definition_in_impl_file.carbon

@@ -107,7 +107,7 @@ impl () as D;
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %.2 as %.1;
+// CHECK:STDOUT: impl @impl: %.loc6_7.2 as %A.ref;
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- decl_in_api_definition_in_impl.impl.carbon
 // CHECK:STDOUT:
@@ -121,6 +121,8 @@ impl () as D;
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1: type = import_ref Main//decl_in_api_definition_in_impl, inst+1, loaded [template = constants.%.1]
 // CHECK:STDOUT:   %import_ref.2 = import_ref Main//decl_in_api_definition_in_impl, inst+3, unloaded
+// CHECK:STDOUT:   %import_ref.3: type = import_ref Main//decl_in_api_definition_in_impl, inst+7, loaded [template = constants.%.2]
+// CHECK:STDOUT:   %import_ref.4: type = import_ref Main//decl_in_api_definition_in_impl, inst+8, loaded [template = constants.%.1]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -147,7 +149,7 @@ impl () as D;
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %.2 as %.1 {
+// CHECK:STDOUT: impl @impl: imports.%import_ref.3 as imports.%import_ref.4 {
 // CHECK:STDOUT:   %.loc6_14: <witness> = interface_witness () [template = constants.%.3]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
@@ -171,6 +173,8 @@ impl () as D;
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1 = import_ref Main//decl_in_api_definition_in_impl, inst+1, unloaded
 // CHECK:STDOUT:   %import_ref.2 = import_ref Main//decl_in_api_definition_in_impl, inst+3, unloaded
+// CHECK:STDOUT:   %import_ref.3: type = import_ref Main//decl_in_api_definition_in_impl, inst+7, loaded [template = constants.%.2]
+// CHECK:STDOUT:   %import_ref.4: type = import_ref Main//decl_in_api_definition_in_impl, inst+8, loaded [template = constants.%.1]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -187,7 +191,7 @@ impl () as D;
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %.2 as %.1;
+// CHECK:STDOUT: impl @impl: imports.%import_ref.3 as imports.%import_ref.4;
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- decl_only_in_api.carbon
 // CHECK:STDOUT:
@@ -217,7 +221,7 @@ impl () as D;
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %.2 as %.1;
+// CHECK:STDOUT: impl @impl: %.loc6_7.2 as %B.ref;
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- decl_only_in_api.impl.carbon
 // CHECK:STDOUT:
@@ -230,6 +234,8 @@ impl () as D;
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1 = import_ref Main//decl_only_in_api, inst+1, unloaded
 // CHECK:STDOUT:   %import_ref.2 = import_ref Main//decl_only_in_api, inst+3, unloaded
+// CHECK:STDOUT:   %import_ref.3: type = import_ref Main//decl_only_in_api, inst+7, loaded [template = constants.%.2]
+// CHECK:STDOUT:   %import_ref.4: type = import_ref Main//decl_only_in_api, inst+8, loaded [template = constants.%.1]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -246,7 +252,7 @@ impl () as D;
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %.2 as %.1;
+// CHECK:STDOUT: impl @impl: imports.%import_ref.3 as imports.%import_ref.4;
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- decl_in_api_decl_in_impl.carbon
 // CHECK:STDOUT:
@@ -276,7 +282,7 @@ impl () as D;
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %.2 as %.1;
+// CHECK:STDOUT: impl @impl: %.loc6_7.2 as %C.ref;
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_decl_in_api_decl_in_impl.impl.carbon
 // CHECK:STDOUT:
@@ -289,6 +295,8 @@ impl () as D;
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1: type = import_ref Main//decl_in_api_decl_in_impl, inst+1, loaded [template = constants.%.1]
 // CHECK:STDOUT:   %import_ref.2 = import_ref Main//decl_in_api_decl_in_impl, inst+3, unloaded
+// CHECK:STDOUT:   %import_ref.3: type = import_ref Main//decl_in_api_decl_in_impl, inst+7, loaded [template = constants.%.2]
+// CHECK:STDOUT:   %import_ref.4: type = import_ref Main//decl_in_api_decl_in_impl, inst+8, loaded [template = constants.%.1]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -310,7 +318,7 @@ impl () as D;
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %.2 as %.1;
+// CHECK:STDOUT: impl @impl: imports.%import_ref.3 as imports.%import_ref.4;
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- decl_only_in_impl.carbon
 // CHECK:STDOUT:
@@ -348,5 +356,5 @@ impl () as D;
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %.2 as %.1;
+// CHECK:STDOUT: impl @impl: %.loc9_7.2 as %D.ref;
 // CHECK:STDOUT:

+ 1 - 1
toolchain/check/testdata/impl/no_prelude/self_in_class.carbon

@@ -70,7 +70,7 @@ class A {
 // CHECK:STDOUT:   witness = (%Make.decl)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.1 {
+// CHECK:STDOUT: impl @impl: %C.ref as %DefaultConstructible.ref {
 // CHECK:STDOUT:   %Make.decl: %Make.type.2 = fn_decl @Make.2 [template = constants.%Make.2] {} {
 // CHECK:STDOUT:     %Self.ref: type = name_ref Self, @impl.%C.ref [template = constants.%C]
 // CHECK:STDOUT:     %return: ref %C = var <return slot>

+ 4 - 4
toolchain/check/testdata/impl/no_prelude/self_in_signature.carbon

@@ -169,7 +169,7 @@ impl D as SelfNested {
 // CHECK:STDOUT:   witness = (%F.decl)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.1: %C as %.1 {
+// CHECK:STDOUT: impl @impl.1: %C.ref as %UseSelf.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {
 // CHECK:STDOUT:     %self.patt: %C = binding_pattern self
 // CHECK:STDOUT:     %x.patt: %C = binding_pattern x
@@ -190,7 +190,7 @@ impl D as SelfNested {
 // CHECK:STDOUT:   witness = %.loc19
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.2: %D as %.1 {
+// CHECK:STDOUT: impl @impl.2: %D.ref as %UseSelf.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.3 = fn_decl @F.3 [template = constants.%F.3] {
 // CHECK:STDOUT:     %self.patt: %D = binding_pattern self
 // CHECK:STDOUT:     %x.patt: %D = binding_pattern x
@@ -211,7 +211,7 @@ impl D as SelfNested {
 // CHECK:STDOUT:   witness = %.loc23
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.3: %C as %.10 {
+// CHECK:STDOUT: impl @impl.3: %C.ref as %SelfNested.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.5 = fn_decl @F.5 [template = constants.%F.5] {
 // CHECK:STDOUT:     %x.patt: %.19 = binding_pattern x
 // CHECK:STDOUT:   } {
@@ -233,7 +233,7 @@ impl D as SelfNested {
 // CHECK:STDOUT:   witness = %.loc31
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.4: %D as %.10 {
+// CHECK:STDOUT: impl @impl.4: %D.ref as %SelfNested.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.6 = fn_decl @F.6 [template = constants.%F.6] {
 // CHECK:STDOUT:     %x.patt: %.23 = binding_pattern x
 // CHECK:STDOUT:   } {

+ 2 - 2
toolchain/check/testdata/impl/redeclaration.carbon

@@ -78,9 +78,9 @@ impl i32 as I {}
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.1: i32 as %.1;
+// CHECK:STDOUT: impl @impl.1: %.loc13_6.2 as %I.ref.loc13;
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.2: i32 as %.1 {
+// CHECK:STDOUT: impl @impl.2: %.loc19_6.2 as %I.ref {
 // CHECK:STDOUT:   %.loc19_15: <witness> = interface_witness () [template = constants.%.5]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:

+ 2 - 2
toolchain/check/testdata/interface/no_prelude/default_fn.carbon

@@ -61,7 +61,7 @@ class C {
 // CHECK:STDOUT:   witness = (%F.decl)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.1 {
+// CHECK:STDOUT: impl @impl: %C.ref as %I.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {} {}
 // CHECK:STDOUT:   %.loc21: <witness> = interface_witness (%F.decl) [template = constants.%.5]
 // CHECK:STDOUT:
@@ -98,7 +98,7 @@ class C {
 // CHECK:STDOUT:     %c.ref: ref %C = name_ref c, %c
 // CHECK:STDOUT:     %I.ref: type = name_ref I, @C.%I.decl [template = constants.%.1]
 // CHECK:STDOUT:     %F.ref: %.3 = name_ref F, @I.%.loc14 [template = constants.%.4]
-// CHECK:STDOUT:     %.loc17: %F.type.1 = interface_witness_access @impl.%.loc21, element0 [template = constants.%F.2]
+// CHECK:STDOUT:     %.loc17: %F.type.1 = interface_witness_access constants.%.5, element0 [template = constants.%F.2]
 // CHECK:STDOUT:     %F.call: init %.2 = call %.loc17()
 // CHECK:STDOUT:     return
 // CHECK:STDOUT:   }

+ 4 - 2
toolchain/check/testdata/interface/no_prelude/generic.carbon

@@ -204,14 +204,14 @@ fn G(T:! Generic(B)) {
 // CHECK:STDOUT:   interface;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.1: %C as %.8 {
+// CHECK:STDOUT: impl @impl.1: %Self.ref as %.loc14_17 {
 // CHECK:STDOUT:   %.loc14_21: <witness> = interface_witness () [template = constants.%.9]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   witness = %.loc14_21
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.2: %C as %.10 {
+// CHECK:STDOUT: impl @impl.2: %Self.ref as %.loc15_22 {
 // CHECK:STDOUT:   %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {} {
 // CHECK:STDOUT:     %X.ref: type = name_ref X, file.%X.decl [template = constants.%X]
 // CHECK:STDOUT:     %return: ref %X = var <return slot>
@@ -232,11 +232,13 @@ fn G(T:! Generic(B)) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT:   impl_decl @impl.1 [template] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%C [template = constants.%C]
 // CHECK:STDOUT:     %Simple.ref: %Simple.type = name_ref Simple, file.%Simple.decl [template = constants.%Simple]
 // CHECK:STDOUT:     %C.ref: type = name_ref C, file.%C.decl [template = constants.%C]
 // CHECK:STDOUT:     %.loc14_17: type = interface_type @Simple, @Simple(constants.%C) [template = constants.%.8]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   impl_decl @impl.2 [template] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%C [template = constants.%C]
 // CHECK:STDOUT:     %WithAssocFn.ref: %WithAssocFn.type = name_ref WithAssocFn, file.%WithAssocFn.decl [template = constants.%WithAssocFn]
 // CHECK:STDOUT:     %C.ref: type = name_ref C, file.%C.decl [template = constants.%C]
 // CHECK:STDOUT:     %.loc15_22: type = interface_type @WithAssocFn, @WithAssocFn(constants.%C) [template = constants.%.10]

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

@@ -161,7 +161,7 @@ impl C as AddWith(C) {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.7 {
+// CHECK:STDOUT: impl @impl: %C.ref.loc7_6 as %.loc7_18 {
 // CHECK:STDOUT:   %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {} {}
 // CHECK:STDOUT:   %.loc7_22: <witness> = interface_witness (%F.decl) [template = constants.%.10]
 // CHECK:STDOUT:

+ 5 - 5
toolchain/check/testdata/interface/no_prelude/generic_vs_params.carbon

@@ -206,35 +206,35 @@ interface A(T: type) {}
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.1: %X as %.1 {
+// CHECK:STDOUT: impl @impl.1: %X.ref as %NotGenericNoParams.ref {
 // CHECK:STDOUT:   %.loc14: <witness> = interface_witness () [template = constants.%.10]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   witness = %.loc14
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.2: %X as %.3 {
+// CHECK:STDOUT: impl @impl.2: %X.ref as %.loc15_30 {
 // CHECK:STDOUT:   %.loc15_33: <witness> = interface_witness () [template = constants.%.10]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   witness = %.loc15_33
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.3: %X as %.11 {
+// CHECK:STDOUT: impl @impl.3: %X.ref.loc16_6 as %.loc16_27 {
 // CHECK:STDOUT:   %.loc16_31: <witness> = interface_witness () [template = constants.%.10]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   witness = %.loc16_31
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.4: %X as %.5 {
+// CHECK:STDOUT: impl @impl.4: %X.ref.loc17_6 as %GenericNoParams.ref {
 // CHECK:STDOUT:   %.loc17: <witness> = interface_witness () [template = constants.%.10]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   witness = %.loc17
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.5: %X as %.13 {
+// CHECK:STDOUT: impl @impl.5: %X.ref.loc18_6 as %.loc18_32 {
 // CHECK:STDOUT:   %.loc18_36: <witness> = interface_witness () [template = constants.%.10]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:

+ 6 - 4
toolchain/check/testdata/interface/no_prelude/import_interface_decl.carbon

@@ -38,7 +38,7 @@ impl library "[[@TEST_NAME]]";
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @A;
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %.2 as %.1;
+// CHECK:STDOUT: impl @impl: %.loc3_7.2 as %A.ref;
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- a.impl.carbon
 // CHECK:STDOUT:
@@ -48,12 +48,14 @@ impl library "[[@TEST_NAME]]";
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref = import_ref Main//a, inst+1, unloaded
+// CHECK:STDOUT:   %import_ref.1 = import_ref Main//a, inst+1, unloaded
+// CHECK:STDOUT:   %import_ref.2: type = import_ref Main//a, inst+5, loaded [template = constants.%.2]
+// CHECK:STDOUT:   %import_ref.3: type = import_ref Main//a, inst+6, loaded [template = constants.%.1]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [template] {
-// CHECK:STDOUT:     .A = imports.%import_ref
+// CHECK:STDOUT:     .A = imports.%import_ref.1
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %default.import.loc1_6.1 = import <invalid>
 // CHECK:STDOUT:   %default.import.loc1_6.2 = import <invalid>
@@ -61,5 +63,5 @@ impl library "[[@TEST_NAME]]";
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @A;
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %.2 as %.1;
+// CHECK:STDOUT: impl @impl: imports.%import_ref.2 as imports.%import_ref.3;
 // CHECK:STDOUT:

+ 4 - 4
toolchain/check/testdata/operators/overloaded/add.carbon

@@ -151,7 +151,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   witness = (imports.%import_ref.8)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.1: %C as %.3 {
+// CHECK:STDOUT: impl @impl.1: %C.ref as %Add.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.1 = fn_decl @Op.1 [template = constants.%Op.1] {
 // CHECK:STDOUT:     %self.patt: %C = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -172,7 +172,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   witness = %.loc17
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.2: %C as %.7 {
+// CHECK:STDOUT: impl @impl.2: %C.ref as %AddAssign.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.3 = fn_decl @Op.3 [template = constants.%Op.3] {
 // CHECK:STDOUT:     %self.patt: %.8 = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -231,7 +231,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %a.ref: %C = name_ref a, %a
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %Op.ref: %.11 = name_ref Op, imports.%import_ref.3 [template = constants.%.12]
-// CHECK:STDOUT:   %.loc27_12.1: %Op.type.2 = interface_witness_access @impl.1.%.loc17, element0 [template = constants.%Op.1]
+// CHECK:STDOUT:   %.loc27_12.1: %Op.type.2 = interface_witness_access constants.%.5, element0 [template = constants.%Op.1]
 // CHECK:STDOUT:   %.loc27_12.2: <bound method> = bound_method %a.ref, %.loc27_12.1
 // CHECK:STDOUT:   %.loc26: ref %C = splice_block %return {}
 // CHECK:STDOUT:   %Op.call: init %C = call %.loc27_12.2(%a.ref, %b.ref) to %.loc26
@@ -244,7 +244,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %.loc31_3.1: ref %C = deref %a.ref
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %Op.ref: %.13 = name_ref Op, imports.%import_ref.7 [template = constants.%.14]
-// CHECK:STDOUT:   %.loc31_6.1: %Op.type.4 = interface_witness_access @impl.2.%.loc22, element0 [template = constants.%Op.3]
+// CHECK:STDOUT:   %.loc31_6.1: %Op.type.4 = interface_witness_access constants.%.10, element0 [template = constants.%Op.3]
 // CHECK:STDOUT:   %.loc31_6.2: <bound method> = bound_method %.loc31_3.1, %.loc31_6.1
 // CHECK:STDOUT:   %.loc31_3.2: %.8 = addr_of %.loc31_3.1
 // CHECK:STDOUT:   %Op.call: init %.4 = call %.loc31_6.2(%.loc31_3.2, %b.ref)

+ 4 - 4
toolchain/check/testdata/operators/overloaded/bit_and.carbon

@@ -151,7 +151,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   witness = (imports.%import_ref.8)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.1: %C as %.3 {
+// CHECK:STDOUT: impl @impl.1: %C.ref as %BitAnd.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.1 = fn_decl @Op.1 [template = constants.%Op.1] {
 // CHECK:STDOUT:     %self.patt: %C = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -172,7 +172,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   witness = %.loc17
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.2: %C as %.7 {
+// CHECK:STDOUT: impl @impl.2: %C.ref as %BitAndAssign.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.3 = fn_decl @Op.3 [template = constants.%Op.3] {
 // CHECK:STDOUT:     %self.patt: %.8 = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -231,7 +231,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %a.ref: %C = name_ref a, %a
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %Op.ref: %.11 = name_ref Op, imports.%import_ref.3 [template = constants.%.12]
-// CHECK:STDOUT:   %.loc27_12.1: %Op.type.2 = interface_witness_access @impl.1.%.loc17, element0 [template = constants.%Op.1]
+// CHECK:STDOUT:   %.loc27_12.1: %Op.type.2 = interface_witness_access constants.%.5, element0 [template = constants.%Op.1]
 // CHECK:STDOUT:   %.loc27_12.2: <bound method> = bound_method %a.ref, %.loc27_12.1
 // CHECK:STDOUT:   %.loc26: ref %C = splice_block %return {}
 // CHECK:STDOUT:   %Op.call: init %C = call %.loc27_12.2(%a.ref, %b.ref) to %.loc26
@@ -244,7 +244,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %.loc31_3.1: ref %C = deref %a.ref
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %Op.ref: %.13 = name_ref Op, imports.%import_ref.7 [template = constants.%.14]
-// CHECK:STDOUT:   %.loc31_6.1: %Op.type.4 = interface_witness_access @impl.2.%.loc22, element0 [template = constants.%Op.3]
+// CHECK:STDOUT:   %.loc31_6.1: %Op.type.4 = interface_witness_access constants.%.10, element0 [template = constants.%Op.3]
 // CHECK:STDOUT:   %.loc31_6.2: <bound method> = bound_method %.loc31_3.1, %.loc31_6.1
 // CHECK:STDOUT:   %.loc31_3.2: %.8 = addr_of %.loc31_3.1
 // CHECK:STDOUT:   %Op.call: init %.4 = call %.loc31_6.2(%.loc31_3.2, %b.ref)

+ 2 - 2
toolchain/check/testdata/operators/overloaded/bit_complement.carbon

@@ -96,7 +96,7 @@ fn TestOp(a: C) -> C {
 // CHECK:STDOUT:   witness = (imports.%import_ref.4)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.3 {
+// CHECK:STDOUT: impl @impl: %C.ref as %BitComplement.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.1 = fn_decl @Op.1 [template = constants.%Op.1] {
 // CHECK:STDOUT:     %self.patt: %C = binding_pattern self
 // CHECK:STDOUT:   } {
@@ -138,7 +138,7 @@ fn TestOp(a: C) -> C {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %a.ref: %C = name_ref a, %a
 // CHECK:STDOUT:   %Op.ref: %.7 = name_ref Op, imports.%import_ref.3 [template = constants.%.8]
-// CHECK:STDOUT:   %.loc24_10.1: %Op.type.2 = interface_witness_access @impl.%.loc17, element0 [template = constants.%Op.1]
+// CHECK:STDOUT:   %.loc24_10.1: %Op.type.2 = interface_witness_access constants.%.5, element0 [template = constants.%Op.1]
 // CHECK:STDOUT:   %.loc24_10.2: <bound method> = bound_method %a.ref, %.loc24_10.1
 // CHECK:STDOUT:   %.loc23: ref %C = splice_block %return {}
 // CHECK:STDOUT:   %Op.call: init %C = call %.loc24_10.2(%a.ref) to %.loc23

+ 4 - 4
toolchain/check/testdata/operators/overloaded/bit_or.carbon

@@ -151,7 +151,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   witness = (imports.%import_ref.8)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.1: %C as %.3 {
+// CHECK:STDOUT: impl @impl.1: %C.ref as %BitOr.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.1 = fn_decl @Op.1 [template = constants.%Op.1] {
 // CHECK:STDOUT:     %self.patt: %C = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -172,7 +172,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   witness = %.loc17
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.2: %C as %.7 {
+// CHECK:STDOUT: impl @impl.2: %C.ref as %BitOrAssign.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.3 = fn_decl @Op.3 [template = constants.%Op.3] {
 // CHECK:STDOUT:     %self.patt: %.8 = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -231,7 +231,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %a.ref: %C = name_ref a, %a
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %Op.ref: %.11 = name_ref Op, imports.%import_ref.3 [template = constants.%.12]
-// CHECK:STDOUT:   %.loc27_12.1: %Op.type.2 = interface_witness_access @impl.1.%.loc17, element0 [template = constants.%Op.1]
+// CHECK:STDOUT:   %.loc27_12.1: %Op.type.2 = interface_witness_access constants.%.5, element0 [template = constants.%Op.1]
 // CHECK:STDOUT:   %.loc27_12.2: <bound method> = bound_method %a.ref, %.loc27_12.1
 // CHECK:STDOUT:   %.loc26: ref %C = splice_block %return {}
 // CHECK:STDOUT:   %Op.call: init %C = call %.loc27_12.2(%a.ref, %b.ref) to %.loc26
@@ -244,7 +244,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %.loc31_3.1: ref %C = deref %a.ref
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %Op.ref: %.13 = name_ref Op, imports.%import_ref.7 [template = constants.%.14]
-// CHECK:STDOUT:   %.loc31_6.1: %Op.type.4 = interface_witness_access @impl.2.%.loc22, element0 [template = constants.%Op.3]
+// CHECK:STDOUT:   %.loc31_6.1: %Op.type.4 = interface_witness_access constants.%.10, element0 [template = constants.%Op.3]
 // CHECK:STDOUT:   %.loc31_6.2: <bound method> = bound_method %.loc31_3.1, %.loc31_6.1
 // CHECK:STDOUT:   %.loc31_3.2: %.8 = addr_of %.loc31_3.1
 // CHECK:STDOUT:   %Op.call: init %.4 = call %.loc31_6.2(%.loc31_3.2, %b.ref)

+ 4 - 4
toolchain/check/testdata/operators/overloaded/bit_xor.carbon

@@ -151,7 +151,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   witness = (imports.%import_ref.8)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.1: %C as %.3 {
+// CHECK:STDOUT: impl @impl.1: %C.ref as %BitXor.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.1 = fn_decl @Op.1 [template = constants.%Op.1] {
 // CHECK:STDOUT:     %self.patt: %C = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -172,7 +172,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   witness = %.loc17
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.2: %C as %.7 {
+// CHECK:STDOUT: impl @impl.2: %C.ref as %BitXorAssign.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.3 = fn_decl @Op.3 [template = constants.%Op.3] {
 // CHECK:STDOUT:     %self.patt: %.8 = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -231,7 +231,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %a.ref: %C = name_ref a, %a
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %Op.ref: %.11 = name_ref Op, imports.%import_ref.3 [template = constants.%.12]
-// CHECK:STDOUT:   %.loc27_12.1: %Op.type.2 = interface_witness_access @impl.1.%.loc17, element0 [template = constants.%Op.1]
+// CHECK:STDOUT:   %.loc27_12.1: %Op.type.2 = interface_witness_access constants.%.5, element0 [template = constants.%Op.1]
 // CHECK:STDOUT:   %.loc27_12.2: <bound method> = bound_method %a.ref, %.loc27_12.1
 // CHECK:STDOUT:   %.loc26: ref %C = splice_block %return {}
 // CHECK:STDOUT:   %Op.call: init %C = call %.loc27_12.2(%a.ref, %b.ref) to %.loc26
@@ -244,7 +244,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %.loc31_3.1: ref %C = deref %a.ref
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %Op.ref: %.13 = name_ref Op, imports.%import_ref.7 [template = constants.%.14]
-// CHECK:STDOUT:   %.loc31_6.1: %Op.type.4 = interface_witness_access @impl.2.%.loc22, element0 [template = constants.%Op.3]
+// CHECK:STDOUT:   %.loc31_6.1: %Op.type.4 = interface_witness_access constants.%.10, element0 [template = constants.%Op.3]
 // CHECK:STDOUT:   %.loc31_6.2: <bound method> = bound_method %.loc31_3.1, %.loc31_6.1
 // CHECK:STDOUT:   %.loc31_3.2: %.8 = addr_of %.loc31_3.1
 // CHECK:STDOUT:   %Op.call: init %.4 = call %.loc31_6.2(%.loc31_3.2, %b.ref)

+ 2 - 2
toolchain/check/testdata/operators/overloaded/dec.carbon

@@ -89,7 +89,7 @@ fn TestOp() {
 // CHECK:STDOUT:   witness = (imports.%import_ref.4)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.3 {
+// CHECK:STDOUT: impl @impl: %C.ref as %Dec.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.1 = fn_decl @Op.1 [template = constants.%Op.1] {
 // CHECK:STDOUT:     %self.patt: %.4 = binding_pattern self
 // CHECK:STDOUT:   } {
@@ -133,7 +133,7 @@ fn TestOp() {
 // CHECK:STDOUT:   assign %c.var, %.loc22_16
 // CHECK:STDOUT:   %c.ref: ref %C = name_ref c, %c
 // CHECK:STDOUT:   %Op.ref: %.9 = name_ref Op, imports.%import_ref.3 [template = constants.%.10]
-// CHECK:STDOUT:   %.loc23_3.1: %Op.type.2 = interface_witness_access @impl.%.loc17, element0 [template = constants.%Op.1]
+// CHECK:STDOUT:   %.loc23_3.1: %Op.type.2 = interface_witness_access constants.%.7, element0 [template = constants.%Op.1]
 // CHECK:STDOUT:   %.loc23_3.2: <bound method> = bound_method %c.ref, %.loc23_3.1
 // CHECK:STDOUT:   %.loc23_5: %.4 = addr_of %c.ref
 // CHECK:STDOUT:   %Op.call: init %.5 = call %.loc23_3.2(%.loc23_5)

+ 4 - 4
toolchain/check/testdata/operators/overloaded/div.carbon

@@ -151,7 +151,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   witness = (imports.%import_ref.8)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.1: %C as %.3 {
+// CHECK:STDOUT: impl @impl.1: %C.ref as %Div.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.1 = fn_decl @Op.1 [template = constants.%Op.1] {
 // CHECK:STDOUT:     %self.patt: %C = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -172,7 +172,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   witness = %.loc17
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.2: %C as %.7 {
+// CHECK:STDOUT: impl @impl.2: %C.ref as %DivAssign.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.3 = fn_decl @Op.3 [template = constants.%Op.3] {
 // CHECK:STDOUT:     %self.patt: %.8 = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -231,7 +231,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %a.ref: %C = name_ref a, %a
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %Op.ref: %.11 = name_ref Op, imports.%import_ref.3 [template = constants.%.12]
-// CHECK:STDOUT:   %.loc27_12.1: %Op.type.2 = interface_witness_access @impl.1.%.loc17, element0 [template = constants.%Op.1]
+// CHECK:STDOUT:   %.loc27_12.1: %Op.type.2 = interface_witness_access constants.%.5, element0 [template = constants.%Op.1]
 // CHECK:STDOUT:   %.loc27_12.2: <bound method> = bound_method %a.ref, %.loc27_12.1
 // CHECK:STDOUT:   %.loc26: ref %C = splice_block %return {}
 // CHECK:STDOUT:   %Op.call: init %C = call %.loc27_12.2(%a.ref, %b.ref) to %.loc26
@@ -244,7 +244,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %.loc31_3.1: ref %C = deref %a.ref
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %Op.ref: %.13 = name_ref Op, imports.%import_ref.7 [template = constants.%.14]
-// CHECK:STDOUT:   %.loc31_6.1: %Op.type.4 = interface_witness_access @impl.2.%.loc22, element0 [template = constants.%Op.3]
+// CHECK:STDOUT:   %.loc31_6.1: %Op.type.4 = interface_witness_access constants.%.10, element0 [template = constants.%Op.3]
 // CHECK:STDOUT:   %.loc31_6.2: <bound method> = bound_method %.loc31_3.1, %.loc31_6.1
 // CHECK:STDOUT:   %.loc31_3.2: %.8 = addr_of %.loc31_3.1
 // CHECK:STDOUT:   %Op.call: init %.4 = call %.loc31_6.2(%.loc31_3.2, %b.ref)

+ 5 - 5
toolchain/check/testdata/operators/overloaded/eq.carbon

@@ -191,7 +191,7 @@ fn TestLhsBad(a: D, b: C) -> bool {
 // CHECK:STDOUT:   witness = (imports.%import_ref.5, imports.%import_ref.6)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.3 {
+// CHECK:STDOUT: impl @impl: %C.ref as %Eq.ref {
 // CHECK:STDOUT:   %Equal.decl: %Equal.type.1 = fn_decl @Equal.1 [template = constants.%Equal.1] {
 // CHECK:STDOUT:     %self.patt: %C = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -260,7 +260,7 @@ fn TestLhsBad(a: D, b: C) -> bool {
 // CHECK:STDOUT:   %a.ref: %C = name_ref a, %a
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %Equal.ref: %.7 = name_ref Equal, imports.%import_ref.3 [template = constants.%.8]
-// CHECK:STDOUT:   %.loc12_12.1: %Equal.type.2 = interface_witness_access @impl.%.loc6, element0 [template = constants.%Equal.1]
+// CHECK:STDOUT:   %.loc12_12.1: %Equal.type.2 = interface_witness_access constants.%.5, element0 [template = constants.%Equal.1]
 // CHECK:STDOUT:   %.loc12_12.2: <bound method> = bound_method %a.ref, %.loc12_12.1
 // CHECK:STDOUT:   %Equal.call: init bool = call %.loc12_12.2(%a.ref, %b.ref)
 // CHECK:STDOUT:   %.loc12_16.1: bool = value_of_initializer %Equal.call
@@ -273,7 +273,7 @@ fn TestLhsBad(a: D, b: C) -> bool {
 // CHECK:STDOUT:   %a.ref: %C = name_ref a, %a
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %NotEqual.ref: %.9 = name_ref NotEqual, imports.%import_ref.4 [template = constants.%.10]
-// CHECK:STDOUT:   %.loc16_12.1: %NotEqual.type.2 = interface_witness_access @impl.%.loc6, element1 [template = constants.%NotEqual.1]
+// CHECK:STDOUT:   %.loc16_12.1: %NotEqual.type.2 = interface_witness_access constants.%.5, element1 [template = constants.%NotEqual.1]
 // CHECK:STDOUT:   %.loc16_12.2: <bound method> = bound_method %a.ref, %.loc16_12.1
 // CHECK:STDOUT:   %NotEqual.call: init bool = call %.loc16_12.2(%a.ref, %b.ref)
 // CHECK:STDOUT:   %.loc16_16.1: bool = value_of_initializer %NotEqual.call
@@ -595,7 +595,7 @@ fn TestLhsBad(a: D, b: C) -> bool {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.3 {
+// CHECK:STDOUT: impl @impl: %C.ref as %Eq.ref {
 // CHECK:STDOUT:   %Equal.decl: %Equal.type.1 = fn_decl @Equal.1 [template = constants.%Equal.1] {
 // CHECK:STDOUT:     %self.patt: %C = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -671,7 +671,7 @@ fn TestLhsBad(a: D, b: C) -> bool {
 // CHECK:STDOUT:   %a.ref: %C = name_ref a, %a
 // CHECK:STDOUT:   %b.ref: %D = name_ref b, %b
 // CHECK:STDOUT:   %Equal.ref: %.7 = name_ref Equal, imports.%import_ref.3 [template = constants.%.8]
-// CHECK:STDOUT:   %.loc23_12.1: %Equal.type.2 = interface_witness_access @impl.%.loc7, element0 [template = constants.%Equal.1]
+// CHECK:STDOUT:   %.loc23_12.1: %Equal.type.2 = interface_witness_access constants.%.5, element0 [template = constants.%Equal.1]
 // CHECK:STDOUT:   %.loc23_12.2: <bound method> = bound_method %a.ref, %.loc23_12.1
 // CHECK:STDOUT:   %.loc23_12.3: type = interface_type @ImplicitAs, @ImplicitAs(constants.%C) [template = constants.%.12]
 // CHECK:STDOUT:   %.loc23_12.4: %.13 = specific_constant imports.%import_ref.11, @ImplicitAs(constants.%C) [template = constants.%.14]

+ 4 - 4
toolchain/check/testdata/operators/overloaded/fail_assign_non_ref.carbon

@@ -153,7 +153,7 @@ fn TestAddAssignNonRef(a: C, b: C) {
 // CHECK:STDOUT:   witness = (imports.%import_ref.8)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.1: %C as %.3 {
+// CHECK:STDOUT: impl @impl.1: %C.ref as %Inc.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.1 = fn_decl @Op.1 [template = constants.%Op.1] {
 // CHECK:STDOUT:     %self.patt: %.4 = binding_pattern self
 // CHECK:STDOUT:   } {
@@ -170,7 +170,7 @@ fn TestAddAssignNonRef(a: C, b: C) {
 // CHECK:STDOUT:   witness = %.loc15
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.2: %C as %.8 {
+// CHECK:STDOUT: impl @impl.2: %C.ref as %AddAssign.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.3 = fn_decl @Op.3 [template = constants.%Op.3] {
 // CHECK:STDOUT:     %self.patt: %.4 = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -220,7 +220,7 @@ fn TestAddAssignNonRef(a: C, b: C) {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %a.ref: %C = name_ref a, %a
 // CHECK:STDOUT:   %Op.ref: %.12 = name_ref Op, imports.%import_ref.3 [template = constants.%.13]
-// CHECK:STDOUT:   %.loc30_3.1: %Op.type.2 = interface_witness_access @impl.1.%.loc15, element0 [template = constants.%Op.1]
+// CHECK:STDOUT:   %.loc30_3.1: %Op.type.2 = interface_witness_access constants.%.7, element0 [template = constants.%Op.1]
 // CHECK:STDOUT:   %.loc30_3.2: <bound method> = bound_method %a.ref, %.loc30_3.1
 // CHECK:STDOUT:   %Op.call: init %.5 = call %.loc30_3.2(<invalid>) [template = <error>]
 // CHECK:STDOUT:   return
@@ -231,7 +231,7 @@ fn TestAddAssignNonRef(a: C, b: C) {
 // CHECK:STDOUT:   %a.ref: %C = name_ref a, %a
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %Op.ref: %.14 = name_ref Op, imports.%import_ref.7 [template = constants.%.15]
-// CHECK:STDOUT:   %.loc40_5.1: %Op.type.4 = interface_witness_access @impl.2.%.loc18, element0 [template = constants.%Op.3]
+// CHECK:STDOUT:   %.loc40_5.1: %Op.type.4 = interface_witness_access constants.%.10, element0 [template = constants.%Op.3]
 // CHECK:STDOUT:   %.loc40_5.2: <bound method> = bound_method %a.ref, %.loc40_5.1
 // CHECK:STDOUT:   %Op.call: init %.5 = call %.loc40_5.2(<invalid>) [template = <error>]
 // CHECK:STDOUT:   return

+ 4 - 4
toolchain/check/testdata/operators/overloaded/fail_no_impl_for_arg.carbon

@@ -208,7 +208,7 @@ fn TestAssign(b: D) {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.1: %C as %.3 {
+// CHECK:STDOUT: impl @impl.1: %C.ref as %Add.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.1 = fn_decl @Op.1 [template = constants.%Op.1] {
 // CHECK:STDOUT:     %self.patt: %C = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -229,7 +229,7 @@ fn TestAssign(b: D) {
 // CHECK:STDOUT:   witness = %.loc16
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.2: %C as %.6 {
+// CHECK:STDOUT: impl @impl.2: %C.ref as %AddAssign.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.3 = fn_decl @Op.3 [template = constants.%Op.3] {
 // CHECK:STDOUT:     %self.patt: %.7 = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -286,7 +286,7 @@ fn TestAssign(b: D) {
 // CHECK:STDOUT:   %a.ref: %C = name_ref a, %a
 // CHECK:STDOUT:   %b.ref: %D = name_ref b, %b
 // CHECK:STDOUT:   %Op.ref: %.11 = name_ref Op, imports.%import_ref.3 [template = constants.%.12]
-// CHECK:STDOUT:   %.loc34_12.1: %Op.type.2 = interface_witness_access @impl.1.%.loc16, element0 [template = constants.%Op.1]
+// CHECK:STDOUT:   %.loc34_12.1: %Op.type.2 = interface_witness_access constants.%.5, element0 [template = constants.%Op.1]
 // CHECK:STDOUT:   %.loc34_12.2: <bound method> = bound_method %a.ref, %.loc34_12.1
 // CHECK:STDOUT:   %.loc34_12.3: ref %C = temporary_storage
 // CHECK:STDOUT:   %.loc34_12.4: type = interface_type @ImplicitAs, @ImplicitAs(constants.%C) [template = constants.%.16]
@@ -317,7 +317,7 @@ fn TestAssign(b: D) {
 // CHECK:STDOUT:   %a.ref: ref %C = name_ref a, %a
 // CHECK:STDOUT:   %b.ref: %D = name_ref b, %b
 // CHECK:STDOUT:   %Op.ref: %.20 = name_ref Op, imports.%import_ref.7 [template = constants.%.21]
-// CHECK:STDOUT:   %.loc48_5.1: %Op.type.4 = interface_witness_access @impl.2.%.loc19, element0 [template = constants.%Op.3]
+// CHECK:STDOUT:   %.loc48_5.1: %Op.type.4 = interface_witness_access constants.%.9, element0 [template = constants.%Op.3]
 // CHECK:STDOUT:   %.loc48_5.2: <bound method> = bound_method %a.ref, %.loc48_5.1
 // CHECK:STDOUT:   %.loc48_3: %.7 = addr_of %a.ref
 // CHECK:STDOUT:   %.loc48_5.3: type = interface_type @ImplicitAs, @ImplicitAs(constants.%C) [template = constants.%.16]

+ 4 - 4
toolchain/check/testdata/operators/overloaded/implicit_as.carbon

@@ -177,7 +177,7 @@ fn Test() {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.1: i32 as %.8 {
+// CHECK:STDOUT: impl @impl.1: %.loc15_6.2 as %.loc15_28 {
 // CHECK:STDOUT:   %Convert.decl: %Convert.type.2 = fn_decl @Convert.2 [template = constants.%Convert.2] {
 // CHECK:STDOUT:     %self.patt: i32 = binding_pattern self
 // CHECK:STDOUT:   } {
@@ -196,7 +196,7 @@ fn Test() {
 // CHECK:STDOUT:   witness = %.loc15_32
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.2: %X as %.13 {
+// CHECK:STDOUT: impl @impl.2: %X.ref as %.loc19_26.3 {
 // CHECK:STDOUT:   %Convert.decl: %Convert.type.4 = fn_decl @Convert.3 [template = constants.%Convert.4] {
 // CHECK:STDOUT:     %self.patt: %X = binding_pattern self
 // CHECK:STDOUT:   } {
@@ -278,7 +278,7 @@ fn Test() {
 // CHECK:STDOUT:   %.loc30_11.2: %.14 = specific_constant imports.%import_ref.4, @ImplicitAs(i32) [template = constants.%.15]
 // CHECK:STDOUT:   %Convert.ref.loc30: %.14 = name_ref Convert, %.loc30_11.2 [template = constants.%.15]
 // CHECK:STDOUT:   %.loc30_18.2: ref %X = temporary %.loc30_18.1, %Source.call.loc30
-// CHECK:STDOUT:   %.loc30_11.3: %Convert.type.5 = interface_witness_access @impl.2.%.loc19_32, element0 [template = constants.%Convert.4]
+// CHECK:STDOUT:   %.loc30_11.3: %Convert.type.5 = interface_witness_access constants.%.16, element0 [template = constants.%Convert.4]
 // CHECK:STDOUT:   %.loc30_11.4: <bound method> = bound_method %.loc30_18.2, %.loc30_11.3
 // CHECK:STDOUT:   %.loc30_18.3: %X = bind_value %.loc30_18.2
 // CHECK:STDOUT:   %Convert.call.loc30: init i32 = call %.loc30_11.4(%.loc30_18.3)
@@ -298,7 +298,7 @@ fn Test() {
 // CHECK:STDOUT:   %Convert.ref.loc31: %.9 = name_ref Convert, %.loc31_9.2 [template = constants.%.10]
 // CHECK:STDOUT:   %.loc31_16.3: ref i32 = temporary_storage
 // CHECK:STDOUT:   %.loc31_16.4: ref i32 = temporary %.loc31_16.3, %Source.call.loc31
-// CHECK:STDOUT:   %.loc31_9.3: %Convert.type.3 = interface_witness_access @impl.1.%.loc15_32, element0 [template = constants.%Convert.2]
+// CHECK:STDOUT:   %.loc31_9.3: %Convert.type.3 = interface_witness_access constants.%.11, element0 [template = constants.%Convert.2]
 // CHECK:STDOUT:   %.loc31_9.4: <bound method> = bound_method %.loc31_16.4, %.loc31_9.3
 // CHECK:STDOUT:   %.loc31_9.5: ref %X = temporary_storage
 // CHECK:STDOUT:   %.loc31_16.5: i32 = bind_value %.loc31_16.4

+ 2 - 2
toolchain/check/testdata/operators/overloaded/inc.carbon

@@ -89,7 +89,7 @@ fn TestOp() {
 // CHECK:STDOUT:   witness = (imports.%import_ref.4)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.3 {
+// CHECK:STDOUT: impl @impl: %C.ref as %Inc.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.1 = fn_decl @Op.1 [template = constants.%Op.1] {
 // CHECK:STDOUT:     %self.patt: %.4 = binding_pattern self
 // CHECK:STDOUT:   } {
@@ -133,7 +133,7 @@ fn TestOp() {
 // CHECK:STDOUT:   assign %c.var, %.loc22_16
 // CHECK:STDOUT:   %c.ref: ref %C = name_ref c, %c
 // CHECK:STDOUT:   %Op.ref: %.9 = name_ref Op, imports.%import_ref.3 [template = constants.%.10]
-// CHECK:STDOUT:   %.loc23_3.1: %Op.type.2 = interface_witness_access @impl.%.loc17, element0 [template = constants.%Op.1]
+// CHECK:STDOUT:   %.loc23_3.1: %Op.type.2 = interface_witness_access constants.%.7, element0 [template = constants.%Op.1]
 // CHECK:STDOUT:   %.loc23_3.2: <bound method> = bound_method %c.ref, %.loc23_3.1
 // CHECK:STDOUT:   %.loc23_5: %.4 = addr_of %c.ref
 // CHECK:STDOUT:   %Op.call: init %.5 = call %.loc23_3.2(%.loc23_5)

+ 4 - 4
toolchain/check/testdata/operators/overloaded/left_shift.carbon

@@ -151,7 +151,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   witness = (imports.%import_ref.8)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.1: %C as %.3 {
+// CHECK:STDOUT: impl @impl.1: %C.ref as %LeftShift.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.1 = fn_decl @Op.1 [template = constants.%Op.1] {
 // CHECK:STDOUT:     %self.patt: %C = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -172,7 +172,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   witness = %.loc17
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.2: %C as %.7 {
+// CHECK:STDOUT: impl @impl.2: %C.ref as %LeftShiftAssign.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.3 = fn_decl @Op.3 [template = constants.%Op.3] {
 // CHECK:STDOUT:     %self.patt: %.8 = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -231,7 +231,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %a.ref: %C = name_ref a, %a
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %Op.ref: %.11 = name_ref Op, imports.%import_ref.3 [template = constants.%.12]
-// CHECK:STDOUT:   %.loc27_12.1: %Op.type.2 = interface_witness_access @impl.1.%.loc17, element0 [template = constants.%Op.1]
+// CHECK:STDOUT:   %.loc27_12.1: %Op.type.2 = interface_witness_access constants.%.5, element0 [template = constants.%Op.1]
 // CHECK:STDOUT:   %.loc27_12.2: <bound method> = bound_method %a.ref, %.loc27_12.1
 // CHECK:STDOUT:   %.loc26: ref %C = splice_block %return {}
 // CHECK:STDOUT:   %Op.call: init %C = call %.loc27_12.2(%a.ref, %b.ref) to %.loc26
@@ -244,7 +244,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %.loc31_3.1: ref %C = deref %a.ref
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %Op.ref: %.13 = name_ref Op, imports.%import_ref.7 [template = constants.%.14]
-// CHECK:STDOUT:   %.loc31_6.1: %Op.type.4 = interface_witness_access @impl.2.%.loc22, element0 [template = constants.%Op.3]
+// CHECK:STDOUT:   %.loc31_6.1: %Op.type.4 = interface_witness_access constants.%.10, element0 [template = constants.%Op.3]
 // CHECK:STDOUT:   %.loc31_6.2: <bound method> = bound_method %.loc31_3.1, %.loc31_6.1
 // CHECK:STDOUT:   %.loc31_3.2: %.8 = addr_of %.loc31_3.1
 // CHECK:STDOUT:   %Op.call: init %.4 = call %.loc31_6.2(%.loc31_3.2, %b.ref)

+ 4 - 4
toolchain/check/testdata/operators/overloaded/mod.carbon

@@ -151,7 +151,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   witness = (imports.%import_ref.8)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.1: %C as %.3 {
+// CHECK:STDOUT: impl @impl.1: %C.ref as %Mod.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.1 = fn_decl @Op.1 [template = constants.%Op.1] {
 // CHECK:STDOUT:     %self.patt: %C = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -172,7 +172,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   witness = %.loc17
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.2: %C as %.7 {
+// CHECK:STDOUT: impl @impl.2: %C.ref as %ModAssign.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.3 = fn_decl @Op.3 [template = constants.%Op.3] {
 // CHECK:STDOUT:     %self.patt: %.8 = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -231,7 +231,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %a.ref: %C = name_ref a, %a
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %Op.ref: %.11 = name_ref Op, imports.%import_ref.3 [template = constants.%.12]
-// CHECK:STDOUT:   %.loc27_12.1: %Op.type.2 = interface_witness_access @impl.1.%.loc17, element0 [template = constants.%Op.1]
+// CHECK:STDOUT:   %.loc27_12.1: %Op.type.2 = interface_witness_access constants.%.5, element0 [template = constants.%Op.1]
 // CHECK:STDOUT:   %.loc27_12.2: <bound method> = bound_method %a.ref, %.loc27_12.1
 // CHECK:STDOUT:   %.loc26: ref %C = splice_block %return {}
 // CHECK:STDOUT:   %Op.call: init %C = call %.loc27_12.2(%a.ref, %b.ref) to %.loc26
@@ -244,7 +244,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %.loc31_3.1: ref %C = deref %a.ref
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %Op.ref: %.13 = name_ref Op, imports.%import_ref.7 [template = constants.%.14]
-// CHECK:STDOUT:   %.loc31_6.1: %Op.type.4 = interface_witness_access @impl.2.%.loc22, element0 [template = constants.%Op.3]
+// CHECK:STDOUT:   %.loc31_6.1: %Op.type.4 = interface_witness_access constants.%.10, element0 [template = constants.%Op.3]
 // CHECK:STDOUT:   %.loc31_6.2: <bound method> = bound_method %.loc31_3.1, %.loc31_6.1
 // CHECK:STDOUT:   %.loc31_3.2: %.8 = addr_of %.loc31_3.1
 // CHECK:STDOUT:   %Op.call: init %.4 = call %.loc31_6.2(%.loc31_3.2, %b.ref)

+ 4 - 4
toolchain/check/testdata/operators/overloaded/mul.carbon

@@ -151,7 +151,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   witness = (imports.%import_ref.8)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.1: %C as %.3 {
+// CHECK:STDOUT: impl @impl.1: %C.ref as %Mul.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.1 = fn_decl @Op.1 [template = constants.%Op.1] {
 // CHECK:STDOUT:     %self.patt: %C = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -172,7 +172,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   witness = %.loc17
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.2: %C as %.7 {
+// CHECK:STDOUT: impl @impl.2: %C.ref as %MulAssign.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.3 = fn_decl @Op.3 [template = constants.%Op.3] {
 // CHECK:STDOUT:     %self.patt: %.8 = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -231,7 +231,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %a.ref: %C = name_ref a, %a
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %Op.ref: %.11 = name_ref Op, imports.%import_ref.3 [template = constants.%.12]
-// CHECK:STDOUT:   %.loc27_12.1: %Op.type.2 = interface_witness_access @impl.1.%.loc17, element0 [template = constants.%Op.1]
+// CHECK:STDOUT:   %.loc27_12.1: %Op.type.2 = interface_witness_access constants.%.5, element0 [template = constants.%Op.1]
 // CHECK:STDOUT:   %.loc27_12.2: <bound method> = bound_method %a.ref, %.loc27_12.1
 // CHECK:STDOUT:   %.loc26: ref %C = splice_block %return {}
 // CHECK:STDOUT:   %Op.call: init %C = call %.loc27_12.2(%a.ref, %b.ref) to %.loc26
@@ -244,7 +244,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %.loc31_3.1: ref %C = deref %a.ref
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %Op.ref: %.13 = name_ref Op, imports.%import_ref.7 [template = constants.%.14]
-// CHECK:STDOUT:   %.loc31_6.1: %Op.type.4 = interface_witness_access @impl.2.%.loc22, element0 [template = constants.%Op.3]
+// CHECK:STDOUT:   %.loc31_6.1: %Op.type.4 = interface_witness_access constants.%.10, element0 [template = constants.%Op.3]
 // CHECK:STDOUT:   %.loc31_6.2: <bound method> = bound_method %.loc31_3.1, %.loc31_6.1
 // CHECK:STDOUT:   %.loc31_3.2: %.8 = addr_of %.loc31_3.1
 // CHECK:STDOUT:   %Op.call: init %.4 = call %.loc31_6.2(%.loc31_3.2, %b.ref)

+ 2 - 2
toolchain/check/testdata/operators/overloaded/negate.carbon

@@ -96,7 +96,7 @@ fn TestOp(a: C) -> C {
 // CHECK:STDOUT:   witness = (imports.%import_ref.4)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.3 {
+// CHECK:STDOUT: impl @impl: %C.ref as %Negate.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.1 = fn_decl @Op.1 [template = constants.%Op.1] {
 // CHECK:STDOUT:     %self.patt: %C = binding_pattern self
 // CHECK:STDOUT:   } {
@@ -138,7 +138,7 @@ fn TestOp(a: C) -> C {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %a.ref: %C = name_ref a, %a
 // CHECK:STDOUT:   %Op.ref: %.7 = name_ref Op, imports.%import_ref.3 [template = constants.%.8]
-// CHECK:STDOUT:   %.loc24_10.1: %Op.type.2 = interface_witness_access @impl.%.loc17, element0 [template = constants.%Op.1]
+// CHECK:STDOUT:   %.loc24_10.1: %Op.type.2 = interface_witness_access constants.%.5, element0 [template = constants.%Op.1]
 // CHECK:STDOUT:   %.loc24_10.2: <bound method> = bound_method %a.ref, %.loc24_10.1
 // CHECK:STDOUT:   %.loc23: ref %C = splice_block %return {}
 // CHECK:STDOUT:   %Op.call: init %C = call %.loc24_10.2(%a.ref) to %.loc23

+ 5 - 5
toolchain/check/testdata/operators/overloaded/ordered.carbon

@@ -239,7 +239,7 @@ fn TestGreaterEqual(a: D, b: D) -> bool {
 // CHECK:STDOUT:   witness = (imports.%import_ref.7, imports.%import_ref.8, imports.%import_ref.9, imports.%import_ref.10)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.3 {
+// CHECK:STDOUT: impl @impl: %C.ref as %Ordered.ref {
 // CHECK:STDOUT:   %Less.decl: %Less.type.1 = fn_decl @Less.1 [template = constants.%Less.1] {
 // CHECK:STDOUT:     %self.patt: %C = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -356,7 +356,7 @@ fn TestGreaterEqual(a: D, b: D) -> bool {
 // CHECK:STDOUT:   %a.ref: %C = name_ref a, %a
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %Less.ref: %.7 = name_ref Less, imports.%import_ref.3 [template = constants.%.8]
-// CHECK:STDOUT:   %.loc14_12.1: %Less.type.2 = interface_witness_access @impl.%.loc6, element0 [template = constants.%Less.1]
+// CHECK:STDOUT:   %.loc14_12.1: %Less.type.2 = interface_witness_access constants.%.5, element0 [template = constants.%Less.1]
 // CHECK:STDOUT:   %.loc14_12.2: <bound method> = bound_method %a.ref, %.loc14_12.1
 // CHECK:STDOUT:   %Less.call: init bool = call %.loc14_12.2(%a.ref, %b.ref)
 // CHECK:STDOUT:   %.loc14_15.1: bool = value_of_initializer %Less.call
@@ -369,7 +369,7 @@ fn TestGreaterEqual(a: D, b: D) -> bool {
 // CHECK:STDOUT:   %a.ref: %C = name_ref a, %a
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %LessOrEquivalent.ref: %.9 = name_ref LessOrEquivalent, imports.%import_ref.4 [template = constants.%.10]
-// CHECK:STDOUT:   %.loc18_12.1: %LessOrEquivalent.type.2 = interface_witness_access @impl.%.loc6, element1 [template = constants.%LessOrEquivalent.1]
+// CHECK:STDOUT:   %.loc18_12.1: %LessOrEquivalent.type.2 = interface_witness_access constants.%.5, element1 [template = constants.%LessOrEquivalent.1]
 // CHECK:STDOUT:   %.loc18_12.2: <bound method> = bound_method %a.ref, %.loc18_12.1
 // CHECK:STDOUT:   %LessOrEquivalent.call: init bool = call %.loc18_12.2(%a.ref, %b.ref)
 // CHECK:STDOUT:   %.loc18_16.1: bool = value_of_initializer %LessOrEquivalent.call
@@ -382,7 +382,7 @@ fn TestGreaterEqual(a: D, b: D) -> bool {
 // CHECK:STDOUT:   %a.ref: %C = name_ref a, %a
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %Greater.ref: %.11 = name_ref Greater, imports.%import_ref.5 [template = constants.%.12]
-// CHECK:STDOUT:   %.loc22_12.1: %Greater.type.2 = interface_witness_access @impl.%.loc6, element2 [template = constants.%Greater.1]
+// CHECK:STDOUT:   %.loc22_12.1: %Greater.type.2 = interface_witness_access constants.%.5, element2 [template = constants.%Greater.1]
 // CHECK:STDOUT:   %.loc22_12.2: <bound method> = bound_method %a.ref, %.loc22_12.1
 // CHECK:STDOUT:   %Greater.call: init bool = call %.loc22_12.2(%a.ref, %b.ref)
 // CHECK:STDOUT:   %.loc22_15.1: bool = value_of_initializer %Greater.call
@@ -395,7 +395,7 @@ fn TestGreaterEqual(a: D, b: D) -> bool {
 // CHECK:STDOUT:   %a.ref: %C = name_ref a, %a
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %GreaterOrEquivalent.ref: %.13 = name_ref GreaterOrEquivalent, imports.%import_ref.6 [template = constants.%.14]
-// CHECK:STDOUT:   %.loc26_12.1: %GreaterOrEquivalent.type.2 = interface_witness_access @impl.%.loc6, element3 [template = constants.%GreaterOrEquivalent.1]
+// CHECK:STDOUT:   %.loc26_12.1: %GreaterOrEquivalent.type.2 = interface_witness_access constants.%.5, element3 [template = constants.%GreaterOrEquivalent.1]
 // CHECK:STDOUT:   %.loc26_12.2: <bound method> = bound_method %a.ref, %.loc26_12.1
 // CHECK:STDOUT:   %GreaterOrEquivalent.call: init bool = call %.loc26_12.2(%a.ref, %b.ref)
 // CHECK:STDOUT:   %.loc26_16.1: bool = value_of_initializer %GreaterOrEquivalent.call

+ 4 - 4
toolchain/check/testdata/operators/overloaded/right_shift.carbon

@@ -151,7 +151,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   witness = (imports.%import_ref.8)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.1: %C as %.3 {
+// CHECK:STDOUT: impl @impl.1: %C.ref as %RightShift.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.1 = fn_decl @Op.1 [template = constants.%Op.1] {
 // CHECK:STDOUT:     %self.patt: %C = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -172,7 +172,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   witness = %.loc17
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.2: %C as %.7 {
+// CHECK:STDOUT: impl @impl.2: %C.ref as %RightShiftAssign.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.3 = fn_decl @Op.3 [template = constants.%Op.3] {
 // CHECK:STDOUT:     %self.patt: %.8 = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -231,7 +231,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %a.ref: %C = name_ref a, %a
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %Op.ref: %.11 = name_ref Op, imports.%import_ref.3 [template = constants.%.12]
-// CHECK:STDOUT:   %.loc27_12.1: %Op.type.2 = interface_witness_access @impl.1.%.loc17, element0 [template = constants.%Op.1]
+// CHECK:STDOUT:   %.loc27_12.1: %Op.type.2 = interface_witness_access constants.%.5, element0 [template = constants.%Op.1]
 // CHECK:STDOUT:   %.loc27_12.2: <bound method> = bound_method %a.ref, %.loc27_12.1
 // CHECK:STDOUT:   %.loc26: ref %C = splice_block %return {}
 // CHECK:STDOUT:   %Op.call: init %C = call %.loc27_12.2(%a.ref, %b.ref) to %.loc26
@@ -244,7 +244,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %.loc31_3.1: ref %C = deref %a.ref
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %Op.ref: %.13 = name_ref Op, imports.%import_ref.7 [template = constants.%.14]
-// CHECK:STDOUT:   %.loc31_6.1: %Op.type.4 = interface_witness_access @impl.2.%.loc22, element0 [template = constants.%Op.3]
+// CHECK:STDOUT:   %.loc31_6.1: %Op.type.4 = interface_witness_access constants.%.10, element0 [template = constants.%Op.3]
 // CHECK:STDOUT:   %.loc31_6.2: <bound method> = bound_method %.loc31_3.1, %.loc31_6.1
 // CHECK:STDOUT:   %.loc31_3.2: %.8 = addr_of %.loc31_3.1
 // CHECK:STDOUT:   %Op.call: init %.4 = call %.loc31_6.2(%.loc31_3.2, %b.ref)

+ 4 - 4
toolchain/check/testdata/operators/overloaded/sub.carbon

@@ -151,7 +151,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   witness = (imports.%import_ref.8)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.1: %C as %.3 {
+// CHECK:STDOUT: impl @impl.1: %C.ref as %Sub.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.1 = fn_decl @Op.1 [template = constants.%Op.1] {
 // CHECK:STDOUT:     %self.patt: %C = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -172,7 +172,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   witness = %.loc17
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.2: %C as %.7 {
+// CHECK:STDOUT: impl @impl.2: %C.ref as %SubAssign.ref {
 // CHECK:STDOUT:   %Op.decl: %Op.type.3 = fn_decl @Op.3 [template = constants.%Op.3] {
 // CHECK:STDOUT:     %self.patt: %.8 = binding_pattern self
 // CHECK:STDOUT:     %other.patt: %C = binding_pattern other
@@ -231,7 +231,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %a.ref: %C = name_ref a, %a
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %Op.ref: %.11 = name_ref Op, imports.%import_ref.3 [template = constants.%.12]
-// CHECK:STDOUT:   %.loc27_12.1: %Op.type.2 = interface_witness_access @impl.1.%.loc17, element0 [template = constants.%Op.1]
+// CHECK:STDOUT:   %.loc27_12.1: %Op.type.2 = interface_witness_access constants.%.5, element0 [template = constants.%Op.1]
 // CHECK:STDOUT:   %.loc27_12.2: <bound method> = bound_method %a.ref, %.loc27_12.1
 // CHECK:STDOUT:   %.loc26: ref %C = splice_block %return {}
 // CHECK:STDOUT:   %Op.call: init %C = call %.loc27_12.2(%a.ref, %b.ref) to %.loc26
@@ -244,7 +244,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %.loc31_3.1: ref %C = deref %a.ref
 // CHECK:STDOUT:   %b.ref: %C = name_ref b, %b
 // CHECK:STDOUT:   %Op.ref: %.13 = name_ref Op, imports.%import_ref.7 [template = constants.%.14]
-// CHECK:STDOUT:   %.loc31_6.1: %Op.type.4 = interface_witness_access @impl.2.%.loc22, element0 [template = constants.%Op.3]
+// CHECK:STDOUT:   %.loc31_6.1: %Op.type.4 = interface_witness_access constants.%.10, element0 [template = constants.%Op.3]
 // CHECK:STDOUT:   %.loc31_6.2: <bound method> = bound_method %.loc31_3.1, %.loc31_6.1
 // CHECK:STDOUT:   %.loc31_3.2: %.8 = addr_of %.loc31_3.1
 // CHECK:STDOUT:   %Op.call: init %.4 = call %.loc31_6.2(%.loc31_3.2, %b.ref)

+ 1 - 1
toolchain/check/testdata/where_expr/constraints.carbon

@@ -474,7 +474,7 @@ fn NotEmptyStruct() {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.3 {
+// CHECK:STDOUT: impl @impl: %C.ref as %J.ref {
 // CHECK:STDOUT:   %.loc8: <witness> = interface_witness () [template = constants.%.5]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:

+ 4 - 3
toolchain/lower/mangler.cpp

@@ -42,14 +42,15 @@ auto Mangler::MangleInverseQualifiedNameScope(llvm::raw_ostream& os,
       case CARBON_KIND(SemIR::ImplDecl impl_decl): {
         const auto& impl = sem_ir().impls().Get(impl_decl.impl_id);
 
-        auto interface_type =
-            types().GetAs<SemIR::InterfaceType>(impl.constraint_id);
+        auto interface_type = insts().GetAs<SemIR::InterfaceType>(
+            constant_values().GetConstantInstId(impl.constraint_id));
         const auto& interface =
             sem_ir().interfaces().Get(interface_type.interface_id);
         names_to_render.push_back(
             {.name_scope_id = interface.scope_id, .prefix = ':'});
 
-        CARBON_KIND_SWITCH(types().GetAsInst(impl.self_id)) {
+        CARBON_KIND_SWITCH(insts().Get(constant_values().GetConstantInstId(
+                               impl.self_id))) {
           case CARBON_KIND(SemIR::ClassType class_type): {
             auto next_name_scope_id =
                 sem_ir().classes().Get(class_type.class_id).scope_id;

+ 8 - 1
toolchain/lower/mangler.h

@@ -8,6 +8,7 @@
 #include <string>
 
 #include "toolchain/lower/file_context.h"
+#include "toolchain/sem_ir/constant.h"
 #include "toolchain/sem_ir/ids.h"
 
 namespace Carbon::Lower {
@@ -38,7 +39,13 @@ class Mangler {
 
   auto names() const -> SemIR::NameStoreWrapper { return sem_ir().names(); }
 
-  auto types() const -> SemIR::TypeStore { return sem_ir().types(); }
+  auto insts() const -> const SemIR::InstStore& { return sem_ir().insts(); }
+
+  auto types() const -> const SemIR::TypeStore& { return sem_ir().types(); }
+
+  auto constant_values() const -> const SemIR::ConstantValueStore& {
+    return sem_ir().constant_values();
+  }
 
   FileContext& file_context_;
 };

+ 1 - 0
toolchain/sem_ir/BUILD

@@ -88,6 +88,7 @@ cc_library(
         "file.cpp",
         "function.cpp",
         "generic.cpp",
+        "impl.cpp",
         "name.cpp",
         "type_info.cpp",
     ],

+ 1 - 2
toolchain/sem_ir/constant.h

@@ -143,8 +143,7 @@ class ConstantValueStore {
 // Provides storage for instructions representing deduplicated global constants.
 class ConstantStore {
  public:
-  explicit ConstantStore(File& sem_ir, llvm::BumpPtrAllocator& /*allocator*/)
-      : sem_ir_(sem_ir) {}
+  explicit ConstantStore(File& sem_ir) : sem_ir_(sem_ir) {}
 
   // Adds a new constant instruction, or gets the existing constant with this
   // value. Returns the ID of the constant.

+ 11 - 1
toolchain/sem_ir/file.cpp

@@ -27,11 +27,12 @@ File::File(CheckIRId check_ir_id, IdentifierId package_id,
       library_id_(library_id),
       value_stores_(&value_stores),
       filename_(std::move(filename)),
+      impls_(*this),
       type_blocks_(allocator_),
       name_scopes_(&insts_),
       constant_values_(ConstantId::NotConstant),
       inst_blocks_(allocator_),
-      constants_(*this, allocator_) {
+      constants_(*this) {
   // `type` and the error type are both complete types.
   types_.SetValueRepr(TypeId::TypeType,
                       {.kind = ValueRepr::Copy, .type_id = TypeId::TypeType});
@@ -488,6 +489,15 @@ static auto StringifyTypeExprImpl(const SemIR::File& outer_sem_ir,
       case ValueAsRef::Kind:
       case ValueOfInitializer::Kind:
       case VarStorage::Kind:
+        // We don't know how to print this instruction, but it might have a
+        // constant value that we can print.
+        auto const_inst_id =
+            sem_ir.constant_values().GetConstantInstId(step.inst_id);
+        if (const_inst_id.is_valid() && const_inst_id != step.inst_id) {
+          push_inst_id(const_inst_id);
+          break;
+        }
+
         // We don't need to handle stringification for instructions that don't
         // show up in errors, but make it clear what's going on so that it's
         // clearer when stringification is needed.

+ 4 - 4
toolchain/sem_ir/formatter.cpp

@@ -225,12 +225,12 @@ class FormatterImpl {
     const Impl& impl_info = sem_ir_.impls().Get(id);
     FormatEntityStart("impl", impl_info.generic_id, id);
 
+    llvm::SaveAndRestore impl_scope(scope_, inst_namer_->GetScopeFor(id));
+
     out_ << ": ";
-    FormatType(impl_info.self_id);
+    FormatName(impl_info.self_id);
     out_ << " as ";
-    FormatType(impl_info.constraint_id);
-
-    llvm::SaveAndRestore impl_scope(scope_, inst_namer_->GetScopeFor(id));
+    FormatName(impl_info.constraint_id);
 
     if (impl_info.is_defined()) {
       out_ << ' ';

+ 22 - 0
toolchain/sem_ir/impl.cpp

@@ -0,0 +1,22 @@
+// 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
+
+#include "toolchain/sem_ir/impl.h"
+
+#include "toolchain/sem_ir/file.h"
+
+namespace Carbon::SemIR {
+
+auto ImplStore::GetOrAddLookupBucket(const Impl& impl) -> LookupBucketRef {
+  auto self_id = sem_ir_.constant_values().GetConstantInstId(impl.self_id);
+  auto constraint_id =
+      sem_ir_.constant_values().GetConstantInstId(impl.constraint_id);
+  return LookupBucketRef(
+      *this, lookup_
+                 .Insert(std::pair{self_id, constraint_id},
+                         [] { return ImplOrLookupBucketId::Invalid; })
+                 .value());
+}
+
+}  // namespace Carbon::SemIR

+ 7 - 12
toolchain/sem_ir/impl.h

@@ -6,7 +6,6 @@
 #define CARBON_TOOLCHAIN_SEM_IR_IMPL_H_
 
 #include "common/map.h"
-#include "llvm/ADT/TinyPtrVector.h"
 #include "toolchain/sem_ir/entity_with_params_base.h"
 #include "toolchain/sem_ir/ids.h"
 
@@ -17,9 +16,9 @@ struct ImplFields {
   // lifetime of the interface.
 
   // The type for which the impl is implementing a constraint.
-  TypeId self_id;
+  InstId self_id;
   // The constraint that the impl implements.
-  TypeId constraint_id;
+  InstId constraint_id;
 
   // The following members are set at the `{` of the impl definition.
 
@@ -151,18 +150,13 @@ class ImplStore {
     ImplId single_id_storage_;
   };
 
+  explicit ImplStore(File& sem_ir) : sem_ir_(sem_ir) {}
+
   // Returns a reference to the lookup bucket containing the list of impls with
   // this self type and constraint, or adds a new bucket if this is the first
   // time we've seen an impl of this kind. The lookup bucket reference remains
   // valid until this function is called again.
-  auto GetOrAddLookupBucket(TypeId self_id, TypeId constraint_id)
-      -> LookupBucketRef {
-    return LookupBucketRef(
-        *this, lookup_
-                   .Insert(std::pair{self_id, constraint_id},
-                           [] { return ImplOrLookupBucketId::Invalid; })
-                   .value());
-  }
+  auto GetOrAddLookupBucket(const Impl& impl) -> LookupBucketRef;
 
   // Adds the specified impl to the store. Does not add it to impl lookup.
   auto Add(Impl impl) -> ImplId { return values_.Add(impl); }
@@ -188,8 +182,9 @@ class ImplStore {
   auto size() const -> size_t { return values_.size(); }
 
  private:
+  File& sem_ir_;
   ValueStore<ImplId> values_;
-  Map<std::pair<TypeId, TypeId>, ImplOrLookupBucketId> lookup_;
+  Map<std::pair<InstId, InstId>, ImplOrLookupBucketId> lookup_;
   // Buckets with at least 2 entries, which will be rare; see LookupBucketRef.
   llvm::SmallVector<llvm::SmallVector<ImplId, 2>> lookup_buckets_;
 };