Bläddra i källkod

Fix importing of generic types. (#4196)

Ensure we don't lose the symbolic constant value by mapping through to
the underlying inst ID.
Richard Smith 1 år sedan
förälder
incheckning
91f56f72a5
27 ändrade filer med 142 tillägg och 114 borttagningar
  1. 77 52
      toolchain/check/import_ref.cpp
  2. 1 1
      toolchain/check/testdata/function/builtin/no_prelude/call_from_operator.carbon
  3. 1 1
      toolchain/check/testdata/impl/no_prelude/import_self.carbon
  4. 10 8
      toolchain/check/testdata/impl/no_prelude/interface_args.carbon
  5. 1 1
      toolchain/check/testdata/index/fail_negative_indexing.carbon
  6. 4 3
      toolchain/check/testdata/interface/no_prelude/generic_import.carbon
  7. 1 1
      toolchain/check/testdata/operators/builtin/fail_type_mismatch_once.carbon
  8. 1 1
      toolchain/check/testdata/operators/builtin/fail_unimplemented_op.carbon
  9. 2 2
      toolchain/check/testdata/operators/overloaded/add.carbon
  10. 2 2
      toolchain/check/testdata/operators/overloaded/bit_and.carbon
  11. 1 1
      toolchain/check/testdata/operators/overloaded/bit_complement.carbon
  12. 2 2
      toolchain/check/testdata/operators/overloaded/bit_or.carbon
  13. 2 2
      toolchain/check/testdata/operators/overloaded/bit_xor.carbon
  14. 1 1
      toolchain/check/testdata/operators/overloaded/dec.carbon
  15. 2 2
      toolchain/check/testdata/operators/overloaded/div.carbon
  16. 6 6
      toolchain/check/testdata/operators/overloaded/eq.carbon
  17. 2 2
      toolchain/check/testdata/operators/overloaded/fail_assign_non_ref.carbon
  18. 4 4
      toolchain/check/testdata/operators/overloaded/fail_no_impl.carbon
  19. 2 2
      toolchain/check/testdata/operators/overloaded/fail_no_impl_for_arg.carbon
  20. 1 1
      toolchain/check/testdata/operators/overloaded/inc.carbon
  21. 2 2
      toolchain/check/testdata/operators/overloaded/left_shift.carbon
  22. 2 2
      toolchain/check/testdata/operators/overloaded/mod.carbon
  23. 2 2
      toolchain/check/testdata/operators/overloaded/mul.carbon
  24. 1 1
      toolchain/check/testdata/operators/overloaded/negate.carbon
  25. 8 8
      toolchain/check/testdata/operators/overloaded/ordered.carbon
  26. 2 2
      toolchain/check/testdata/operators/overloaded/right_shift.carbon
  27. 2 2
      toolchain/check/testdata/operators/overloaded/sub.carbon

+ 77 - 52
toolchain/check/import_ref.cpp

@@ -119,6 +119,35 @@ auto VerifySameCanonicalImportIRInst(Context& context, SemIR::InstId prev_id,
   context.DiagnoseDuplicateName(conflict_id, prev_id);
 }
 
+// Returns an instruction that has the specified constant value.
+static auto GetInstWithConstantValue(const SemIR::File& file,
+                                     SemIR::ConstantId const_id)
+    -> SemIR::InstId {
+  if (!const_id.is_valid()) {
+    return SemIR::InstId::Invalid;
+  }
+
+  // For template constants, the corresponding instruction has the desired
+  // constant value.
+  if (!const_id.is_symbolic()) {
+    return file.constant_values().GetInstId(const_id);
+  }
+
+  // For abstract symbolic constants, the corresponding instruction has the
+  // desired constant value.
+  const auto& symbolic_const =
+      file.constant_values().GetSymbolicConstant(const_id);
+  if (!symbolic_const.generic_id.is_valid()) {
+    return file.constant_values().GetInstId(const_id);
+  }
+
+  // For a symbolic constant in a generic, pick the corresponding instruction
+  // out of the eval block for the generic.
+  const auto& generic = file.generics().Get(symbolic_const.generic_id);
+  auto block = generic.GetEvalBlock(symbolic_const.index.region());
+  return file.inst_blocks().Get(block)[symbolic_const.index.index()];
+}
+
 // Resolves an instruction from an imported IR into a constant referring to the
 // current IR.
 //
@@ -237,30 +266,7 @@ class ImportRefResolver {
 
   // Wraps constant evaluation with logic to handle constants.
   auto ResolveConstant(SemIR::ConstantId import_const_id) -> SemIR::ConstantId {
-    if (!import_const_id.is_valid()) {
-      return import_const_id;
-    }
-
-    // For template constants, the corresponding instruction has the desired
-    // constant value.
-    if (!import_const_id.is_symbolic()) {
-      return Resolve(import_ir_.constant_values().GetInstId(import_const_id));
-    }
-
-    // For abstract symbolic constants, the corresponding instruction has the
-    // desired constant value.
-    const auto& symbolic_const =
-        import_ir_.constant_values().GetSymbolicConstant(import_const_id);
-    if (!symbolic_const.generic_id.is_valid()) {
-      return Resolve(import_ir_.constant_values().GetInstId(import_const_id));
-    }
-
-    // For a symbolic constant in a generic, pick the corresponding instruction
-    // out of the eval block for the generic and resolve its constant value.
-    const auto& generic = import_ir_.generics().Get(symbolic_const.generic_id);
-    auto block = generic.GetEvalBlock(symbolic_const.index.region());
-    return Resolve(
-        import_ir_.inst_blocks().Get(block)[symbolic_const.index.index()]);
+    return Resolve(GetInstWithConstantValue(import_ir_, import_const_id));
   }
 
   // Wraps constant evaluation with logic to handle types.
@@ -313,6 +319,12 @@ class ImportRefResolver {
     llvm::SmallVector<SemIR::ImportIRInst> indirect_insts = {};
   };
 
+  // Local information associated with an imported parameter.
+  struct ParamData {
+    SemIR::ConstantId type_const_id;
+    SemIR::ConstantId bind_const_id;
+  };
+
   // Local information associated with an imported generic.
   struct GenericData {
     llvm::SmallVector<SemIR::InstId> bindings;
@@ -419,6 +431,12 @@ class ImportRefResolver {
     return const_id;
   }
 
+  // Returns the ConstantId for an imported ConstantId. Adds unresolved
+  // constants to work_stack_.
+  auto GetLocalConstantId(SemIR::ConstantId const_id) -> SemIR::ConstantId {
+    return GetLocalConstantId(GetInstWithConstantValue(import_ir_, const_id));
+  }
+
   // Returns the local constant InstId for an imported InstId.
   auto GetLocalConstantInstId(SemIR::InstId inst_id) -> SemIR::InstId {
     auto const_id = import_ir_constant_values().Get(inst_id);
@@ -432,7 +450,7 @@ class ImportRefResolver {
   // Returns the ConstantId for a TypeId. Adds unresolved constants to
   // work_stack_.
   auto GetLocalConstantId(SemIR::TypeId type_id) -> SemIR::ConstantId {
-    return GetLocalConstantId(import_ir_.types().GetInstId(type_id));
+    return GetLocalConstantId(import_ir_.types().GetConstantId(type_id));
   }
 
   // Gets the local constant values corresponding to an imported inst block.
@@ -631,36 +649,40 @@ class ImportRefResolver {
   // Returns the ConstantId for each parameter's type. Adds unresolved constants
   // to work_stack_.
   auto GetLocalParamConstantIds(SemIR::InstBlockId param_refs_id)
-      -> llvm::SmallVector<SemIR::ConstantId> {
-    llvm::SmallVector<SemIR::ConstantId> const_ids;
+      -> llvm::SmallVector<ParamData> {
+    llvm::SmallVector<ParamData> param_data;
     if (!param_refs_id.is_valid() ||
         param_refs_id == SemIR::InstBlockId::Empty) {
-      return const_ids;
+      return param_data;
     }
 
     const auto& param_refs = import_ir_.inst_blocks().Get(param_refs_id);
-    const_ids.reserve(param_refs.size());
+    param_data.reserve(param_refs.size());
     for (auto inst_id : param_refs) {
-      const_ids.push_back(
-          GetLocalConstantId(import_ir_.insts().Get(inst_id).type_id()));
+      auto type_const_id =
+          GetLocalConstantId(import_ir_.insts().Get(inst_id).type_id());
 
       // If the parameter is a symbolic binding, build the BindSymbolicName
       // constant.
       auto bind_id = inst_id;
-      if (auto addr =
-              import_ir_.insts().TryGetAs<SemIR::AddrPattern>(bind_id)) {
+      auto bind_inst = import_ir_.insts().Get(bind_id);
+      if (auto addr = bind_inst.TryAs<SemIR::AddrPattern>()) {
         bind_id = addr->inner_id;
+        bind_inst = import_ir_.insts().Get(bind_id);
       }
-      GetLocalConstantId(bind_id);
+      auto bind_const_id = bind_inst.Is<SemIR::BindSymbolicName>()
+                               ? GetLocalConstantId(bind_id)
+                               : SemIR::ConstantId::Invalid;
+      param_data.push_back(
+          {.type_const_id = type_const_id, .bind_const_id = bind_const_id});
     }
-    return const_ids;
+    return param_data;
   }
 
   // Given a param_refs_id and const_ids from GetLocalParamConstantIds, returns
   // a version of param_refs_id localized to the current IR.
-  auto GetLocalParamRefsId(
-      SemIR::InstBlockId param_refs_id,
-      const llvm::SmallVector<SemIR::ConstantId>& const_ids)
+  auto GetLocalParamRefsId(SemIR::InstBlockId param_refs_id,
+                           const llvm::SmallVector<ParamData>& params_data)
       -> SemIR::InstBlockId {
     if (!param_refs_id.is_valid() ||
         param_refs_id == SemIR::InstBlockId::Empty) {
@@ -668,7 +690,7 @@ class ImportRefResolver {
     }
     const auto& param_refs = import_ir_.inst_blocks().Get(param_refs_id);
     llvm::SmallVector<SemIR::InstId> new_param_refs;
-    for (auto [ref_id, const_id] : llvm::zip(param_refs, const_ids)) {
+    for (auto [ref_id, param_data] : llvm::zip(param_refs, params_data)) {
       // Figure out the param structure. This echoes
       // Function::GetParamFromParamRefId.
       // TODO: Consider a different parameter handling to simplify import logic.
@@ -693,7 +715,8 @@ class ImportRefResolver {
 
       // Rebuild the param instruction.
       auto name_id = GetLocalNameId(param_inst.name_id);
-      auto type_id = context_.GetTypeIdForTypeConstant(const_id);
+      auto type_id =
+          context_.GetTypeIdForTypeConstant(param_data.type_const_id);
 
       auto new_param_id = context_.AddInstInNoBlock<SemIR::Param>(
           AddImportIRInst(param_id), {.type_id = type_id, .name_id = name_id});
@@ -712,14 +735,17 @@ class ImportRefResolver {
           }
           case SemIR::BindSymbolicName::Kind: {
             // We already imported a constant value for this symbolic binding.
-            // We can reuse most of it.
-            auto new_bind_inst_id = GetLocalConstantInstId(bind_id);
+            // We can reuse most of it, but update the value to point to our
+            // specific parameter, and preserve the constant value.
             auto new_bind_inst =
                 context_.insts().GetAs<SemIR::BindSymbolicName>(
-                    new_bind_inst_id);
+                    context_.constant_values().GetInstId(
+                        param_data.bind_const_id));
             new_bind_inst.value_id = new_param_id;
             new_param_id = context_.AddInstInNoBlock(AddImportIRInst(bind_id),
                                                      new_bind_inst);
+            context_.constant_values().Set(new_param_id,
+                                           param_data.bind_const_id);
             break;
           }
           default: {
@@ -1252,10 +1278,9 @@ class ImportRefResolver {
 
     // Load constants for the definition.
     auto parent_scope_id = GetLocalNameScopeId(import_class.parent_scope_id);
-    llvm::SmallVector<SemIR::ConstantId> implicit_param_const_ids =
+    auto implicit_param_const_ids =
         GetLocalParamConstantIds(import_class.implicit_param_refs_id);
-    llvm::SmallVector<SemIR::ConstantId> param_const_ids =
-        GetLocalParamConstantIds(import_class.param_refs_id);
+    auto param_const_ids = GetLocalParamConstantIds(import_class.param_refs_id);
     auto generic_data = GetLocalGenericData(import_class.generic_id);
     auto self_const_id = GetLocalConstantId(import_class.self_type_id);
     auto object_repr_const_id =
@@ -1401,13 +1426,13 @@ class ImportRefResolver {
 
     auto return_type_const_id = SemIR::ConstantId::Invalid;
     if (import_function.return_storage_id.is_valid()) {
-      return_type_const_id =
-          GetLocalConstantId(import_function.GetDeclaredReturnType(import_ir_));
+      return_type_const_id = GetLocalConstantId(
+          import_ir_.insts().Get(import_function.return_storage_id).type_id());
     }
     auto parent_scope_id = GetLocalNameScopeId(import_function.parent_scope_id);
-    llvm::SmallVector<SemIR::ConstantId> implicit_param_const_ids =
+    auto implicit_param_const_ids =
         GetLocalParamConstantIds(import_function.implicit_param_refs_id);
-    llvm::SmallVector<SemIR::ConstantId> param_const_ids =
+    auto param_const_ids =
         GetLocalParamConstantIds(import_function.param_refs_id);
     auto generic_data = GetLocalGenericData(import_function.generic_id);
 
@@ -1594,9 +1619,9 @@ class ImportRefResolver {
 
     auto parent_scope_id =
         GetLocalNameScopeId(import_interface.parent_scope_id);
-    llvm::SmallVector<SemIR::ConstantId> implicit_param_const_ids =
+    auto implicit_param_const_ids =
         GetLocalParamConstantIds(import_interface.implicit_param_refs_id);
-    llvm::SmallVector<SemIR::ConstantId> param_const_ids =
+    auto param_const_ids =
         GetLocalParamConstantIds(import_interface.param_refs_id);
     auto generic_data = GetLocalGenericData(import_interface.generic_id);
 

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

@@ -194,7 +194,7 @@ var arr: [i32; 1 + 2] = (3, 4, 3 + 4);
 // CHECK:STDOUT: generic fn @Op.2(constants.%Self: %.2) {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self](%other: %Self) -> %Self;
+// CHECK:STDOUT:   fn[%self: @Op.2.%Self (%Self)](%other: @Op.2.%Self (%Self)) -> @Op.2.%Self (%Self);
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {

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

@@ -173,7 +173,7 @@ fn F(x: (), y: ()) -> () {
 // CHECK:STDOUT: generic fn @Op.2(constants.%Self: %.2) {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self](%other: %Self) -> %Self;
+// CHECK:STDOUT:   fn[%self: @Op.2.%Self (%Self)](%other: @Op.2.%Self (%Self)) -> @Op.2.%Self (%Self);
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @F(%x: %.1, %y: %.1) -> %.1 {

+ 10 - 8
toolchain/check/testdata/impl/no_prelude/interface_args.carbon

@@ -190,13 +190,14 @@ impl A as Factory(B) {
 // CHECK:STDOUT:   %Action: %Action.type = struct_value () [template]
 // CHECK:STDOUT:   %T: type = bind_symbolic_name T 0 [symbolic]
 // CHECK:STDOUT:   %.3: type = interface_type @Action, @Action(%T) [symbolic]
-// CHECK:STDOUT:   %Self: %.3 = bind_symbolic_name Self 1 [symbolic]
+// CHECK:STDOUT:   %Self.1: @Action.%.1 (%.3) = bind_symbolic_name Self 1 [symbolic]
 // CHECK:STDOUT:   %Op.type.1: type = fn_type @Op.1 [template]
 // CHECK:STDOUT:   %Op.1: %Op.type.1 = struct_value () [template]
 // CHECK:STDOUT:   %Op.type.2: type = fn_type @Op.1, @Action(%T) [symbolic]
 // CHECK:STDOUT:   %.4: type = assoc_entity_type %.3, %Op.type.2 [symbolic]
 // CHECK:STDOUT:   %.5: %.4 = assoc_entity element0, imports.%import_ref.7 [symbolic]
 // CHECK:STDOUT:   %Op.2: %Op.type.2 = struct_value () [symbolic]
+// CHECK:STDOUT:   %Self.2: %.3 = bind_symbolic_name Self 1 [symbolic]
 // CHECK:STDOUT:   %.6: type = interface_type @Action, @Action(%B) [template]
 // CHECK:STDOUT:   %F.type: type = fn_type @F [template]
 // CHECK:STDOUT:   %F: %F.type = struct_value () [template]
@@ -248,7 +249,7 @@ impl A as Factory(B) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: !definition:
 // CHECK:STDOUT:   %.1: type = interface_type @Action, @Action(%T) [symbolic = %.1 (constants.%.3)]
-// CHECK:STDOUT:   %Self: %.3 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:   %Self: %.3 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self.2)]
 // CHECK:STDOUT:   %Op.type: type = fn_type @Op.1, @Action(%T) [symbolic = %Op.type (constants.%Op.type.2)]
 // CHECK:STDOUT:   %Op: @Action.%Op.type (%Op.type.2) = struct_value () [symbolic = %Op (constants.%Op.2)]
 // CHECK:STDOUT:   %.2: type = assoc_entity_type @Action.%.1 (%.3), @Action.%Op.type (%Op.type.2) [symbolic = %.2 (constants.%.4)]
@@ -277,7 +278,7 @@ impl A as Factory(B) {
 // CHECK:STDOUT:   .Self = imports.%import_ref.6
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: generic fn @Op.1(constants.%T: type, constants.%Self: %.3) {
+// CHECK:STDOUT: generic fn @Op.1(constants.%T: type, constants.%Self.1: @Action.%.1 (%.3)) {
 // CHECK:STDOUT:
 // CHECK:STDOUT:   fn();
 // CHECK:STDOUT: }
@@ -310,7 +311,7 @@ impl A as Factory(B) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: !definition:
 // CHECK:STDOUT:   %.1 => constants.%.6
-// CHECK:STDOUT:   %Self => constants.%Self
+// CHECK:STDOUT:   %Self => constants.%Self.2
 // CHECK:STDOUT:   %Op.type => constants.%Op.type.3
 // CHECK:STDOUT:   %Op => constants.%Op.3
 // CHECK:STDOUT:   %.2 => constants.%.8
@@ -328,13 +329,14 @@ impl A as Factory(B) {
 // CHECK:STDOUT:   %Action: %Action.type = struct_value () [template]
 // CHECK:STDOUT:   %T: type = bind_symbolic_name T 0 [symbolic]
 // CHECK:STDOUT:   %.3: type = interface_type @Action, @Action(%T) [symbolic]
-// CHECK:STDOUT:   %Self: %.3 = bind_symbolic_name Self 1 [symbolic]
+// CHECK:STDOUT:   %Self.1: @Action.%.1 (%.3) = bind_symbolic_name Self 1 [symbolic]
 // CHECK:STDOUT:   %Op.type.1: type = fn_type @Op [template]
 // CHECK:STDOUT:   %Op.1: %Op.type.1 = struct_value () [template]
 // CHECK:STDOUT:   %Op.type.2: type = fn_type @Op, @Action(%T) [symbolic]
 // CHECK:STDOUT:   %.4: type = assoc_entity_type %.3, %Op.type.2 [symbolic]
 // CHECK:STDOUT:   %.5: %.4 = assoc_entity element0, imports.%import_ref.7 [symbolic]
 // CHECK:STDOUT:   %Op.2: %Op.type.2 = struct_value () [symbolic]
+// CHECK:STDOUT:   %Self.2: %.3 = bind_symbolic_name Self 1 [symbolic]
 // CHECK:STDOUT:   %.6: type = interface_type @Action, @Action(%B) [template]
 // CHECK:STDOUT:   %G.type: type = fn_type @G [template]
 // CHECK:STDOUT:   %G: %G.type = struct_value () [template]
@@ -386,7 +388,7 @@ impl A as Factory(B) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: !definition:
 // CHECK:STDOUT:   %.1: type = interface_type @Action, @Action(%T) [symbolic = %.1 (constants.%.3)]
-// CHECK:STDOUT:   %Self: %.3 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:   %Self: %.3 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self.2)]
 // CHECK:STDOUT:   %Op.type: type = fn_type @Op, @Action(%T) [symbolic = %Op.type (constants.%Op.type.2)]
 // CHECK:STDOUT:   %Op: @Action.%Op.type (%Op.type.2) = struct_value () [symbolic = %Op (constants.%Op.2)]
 // CHECK:STDOUT:   %.2: type = assoc_entity_type @Action.%.1 (%.3), @Action.%Op.type (%Op.type.2) [symbolic = %.2 (constants.%.4)]
@@ -420,7 +422,7 @@ impl A as Factory(B) {
 // CHECK:STDOUT:   .Self = imports.%import_ref.12
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: generic fn @Op(constants.%T: type, constants.%Self: %.3) {
+// CHECK:STDOUT: generic fn @Op(constants.%T: type, constants.%Self.1: @Action.%.1 (%.3)) {
 // CHECK:STDOUT:
 // CHECK:STDOUT:   fn();
 // CHECK:STDOUT: }
@@ -453,7 +455,7 @@ impl A as Factory(B) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: !definition:
 // CHECK:STDOUT:   %.1 => constants.%.8
-// CHECK:STDOUT:   %Self => constants.%Self
+// CHECK:STDOUT:   %Self => constants.%Self.2
 // CHECK:STDOUT:   %Op.type => constants.%Op.type.3
 // CHECK:STDOUT:   %Op => constants.%Op.3
 // CHECK:STDOUT:   %.2 => constants.%.9

+ 1 - 1
toolchain/check/testdata/index/fail_negative_indexing.carbon

@@ -91,7 +91,7 @@ var b: i32 = a[-10];
 // CHECK:STDOUT: generic fn @Op(constants.%Self: %.8) {
 // CHECK:STDOUT:   %Self: %.8 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self]() -> %Self;
+// CHECK:STDOUT:   fn[%self: @Op.%Self (%Self)]() -> @Op.%Self (%Self);
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {

+ 4 - 3
toolchain/check/testdata/interface/no_prelude/generic_import.carbon

@@ -100,13 +100,14 @@ impl C as AddWith(C) {
 // CHECK:STDOUT:   %AddWith: %AddWith.type = struct_value () [template]
 // CHECK:STDOUT:   %T: type = bind_symbolic_name T 0 [symbolic]
 // CHECK:STDOUT:   %.3: type = interface_type @AddWith, @AddWith(%T) [symbolic]
-// CHECK:STDOUT:   %Self: %.3 = bind_symbolic_name Self 1 [symbolic]
+// CHECK:STDOUT:   %Self.1: @AddWith.%.1 (%.3) = bind_symbolic_name Self 1 [symbolic]
 // CHECK:STDOUT:   %F.type.1: type = fn_type @F.1 [template]
 // CHECK:STDOUT:   %F.1: %F.type.1 = struct_value () [template]
 // CHECK:STDOUT:   %F.type.2: type = fn_type @F.1, @AddWith(%T) [symbolic]
 // CHECK:STDOUT:   %.4: type = assoc_entity_type %.3, %F.type.2 [symbolic]
 // CHECK:STDOUT:   %.5: %.4 = assoc_entity element0, imports.%import_ref.2 [symbolic]
 // CHECK:STDOUT:   %F.2: %F.type.2 = struct_value () [symbolic]
+// CHECK:STDOUT:   %Self.2: %.3 = bind_symbolic_name Self 1 [symbolic]
 // CHECK:STDOUT:   %.6: type = interface_type @AddWith, @AddWith(%C) [template]
 // CHECK:STDOUT:   %F.type.3: type = fn_type @F.2 [template]
 // CHECK:STDOUT:   %F.3: %F.type.3 = struct_value () [template]
@@ -143,7 +144,7 @@ impl C as AddWith(C) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: !definition:
 // CHECK:STDOUT:   %.1: type = interface_type @AddWith, @AddWith(%T) [symbolic = %.1 (constants.%.3)]
-// CHECK:STDOUT:   %Self: %.3 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:   %Self: %.3 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self.2)]
 // CHECK:STDOUT:   %F.type: type = fn_type @F.1, @AddWith(%T) [symbolic = %F.type (constants.%F.type.2)]
 // CHECK:STDOUT:   %F: @AddWith.%F.type (%F.type.2) = struct_value () [symbolic = %F (constants.%F.2)]
 // CHECK:STDOUT:   %.2: type = assoc_entity_type @AddWith.%.1 (%.3), @AddWith.%F.type (%F.type.2) [symbolic = %.2 (constants.%.4)]
@@ -171,7 +172,7 @@ impl C as AddWith(C) {
 // CHECK:STDOUT:   .Self = constants.%C
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: generic fn @F.1(constants.%T: type, constants.%Self: %.3) {
+// CHECK:STDOUT: generic fn @F.1(constants.%T: type, constants.%Self.1: @AddWith.%.1 (%.3)) {
 // CHECK:STDOUT:
 // CHECK:STDOUT:   fn();
 // CHECK:STDOUT: }

+ 1 - 1
toolchain/check/testdata/operators/builtin/fail_type_mismatch_once.carbon

@@ -93,6 +93,6 @@ fn Main() -> i32 {
 // CHECK:STDOUT: generic fn @Op(constants.%Self: %.4) {
 // CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self](%other: %Self) -> %Self;
+// CHECK:STDOUT:   fn[%self: @Op.%Self (%Self)](%other: @Op.%Self (%Self)) -> @Op.%Self (%Self);
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 1 - 1
toolchain/check/testdata/operators/builtin/fail_unimplemented_op.carbon

@@ -86,6 +86,6 @@ fn Main() -> i32 {
 // CHECK:STDOUT: generic fn @Op(constants.%Self: %.4) {
 // CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self](%other: %Self) -> %Self;
+// CHECK:STDOUT:   fn[%self: @Op.%Self (%Self)](%other: @Op.%Self (%Self)) -> @Op.%Self (%Self);
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

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

@@ -195,7 +195,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT: generic fn @Op.2(constants.%Self.1: %.2) {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self.1](%other: %Self.1) -> %Self.1;
+// CHECK:STDOUT:   fn[%self: @Op.2.%Self (%Self.1)](%other: @Op.2.%Self (%Self.1)) -> @Op.2.%Self (%Self.1);
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc23_14.3: %.7](@impl.2.%other.loc23_24.2: %C) {
@@ -207,7 +207,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %Self: %.6 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)]
 // CHECK:STDOUT:   %.2: type = ptr_type @Op.4.%Self (%Self.2) [symbolic = %.2 (constants.%.8)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[addr %self: %.8](%other: %Self.2);
+// CHECK:STDOUT:   fn[addr %self: @Op.4.%.2 (%.8)](%other: @Op.4.%Self (%Self.2));
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @TestOp(%a: %C, %b: %C) -> %return: %C {

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

@@ -195,7 +195,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT: generic fn @Op.2(constants.%Self.1: %.2) {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self.1](%other: %Self.1) -> %Self.1;
+// CHECK:STDOUT:   fn[%self: @Op.2.%Self (%Self.1)](%other: @Op.2.%Self (%Self.1)) -> @Op.2.%Self (%Self.1);
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc23_14.3: %.7](@impl.2.%other.loc23_24.2: %C) {
@@ -207,7 +207,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %Self: %.6 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)]
 // CHECK:STDOUT:   %.2: type = ptr_type @Op.4.%Self (%Self.2) [symbolic = %.2 (constants.%.8)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[addr %self: %.8](%other: %Self.2);
+// CHECK:STDOUT:   fn[addr %self: @Op.4.%.2 (%.8)](%other: @Op.4.%Self (%Self.2));
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @TestOp(%a: %C, %b: %C) -> %return: %C {

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

@@ -123,7 +123,7 @@ fn TestOp(a: C) -> C {
 // CHECK:STDOUT: generic fn @Op.2(constants.%Self: %.2) {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self]() -> %Self;
+// CHECK:STDOUT:   fn[%self: @Op.2.%Self (%Self)]() -> @Op.2.%Self (%Self);
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @TestOp(%a: %C) -> %return: %C {

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

@@ -195,7 +195,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT: generic fn @Op.2(constants.%Self.1: %.2) {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self.1](%other: %Self.1) -> %Self.1;
+// CHECK:STDOUT:   fn[%self: @Op.2.%Self (%Self.1)](%other: @Op.2.%Self (%Self.1)) -> @Op.2.%Self (%Self.1);
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc23_14.3: %.7](@impl.2.%other.loc23_24.2: %C) {
@@ -207,7 +207,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %Self: %.6 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)]
 // CHECK:STDOUT:   %.2: type = ptr_type @Op.4.%Self (%Self.2) [symbolic = %.2 (constants.%.8)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[addr %self: %.8](%other: %Self.2);
+// CHECK:STDOUT:   fn[addr %self: @Op.4.%.2 (%.8)](%other: @Op.4.%Self (%Self.2));
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @TestOp(%a: %C, %b: %C) -> %return: %C {

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

@@ -195,7 +195,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT: generic fn @Op.2(constants.%Self.1: %.2) {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self.1](%other: %Self.1) -> %Self.1;
+// CHECK:STDOUT:   fn[%self: @Op.2.%Self (%Self.1)](%other: @Op.2.%Self (%Self.1)) -> @Op.2.%Self (%Self.1);
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc23_14.3: %.7](@impl.2.%other.loc23_24.2: %C) {
@@ -207,7 +207,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %Self: %.6 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)]
 // CHECK:STDOUT:   %.2: type = ptr_type @Op.4.%Self (%Self.2) [symbolic = %.2 (constants.%.8)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[addr %self: %.8](%other: %Self.2);
+// CHECK:STDOUT:   fn[addr %self: @Op.4.%.2 (%.8)](%other: @Op.4.%Self (%Self.2));
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @TestOp(%a: %C, %b: %C) -> %return: %C {

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

@@ -113,7 +113,7 @@ fn TestOp() {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:   %.2: type = ptr_type @Op.2.%Self (%Self) [symbolic = %.2 (constants.%.5)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[addr %self: %.5]();
+// CHECK:STDOUT:   fn[addr %self: @Op.2.%.2 (%.5)]();
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @TestOp() {

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

@@ -195,7 +195,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT: generic fn @Op.2(constants.%Self.1: %.2) {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self.1](%other: %Self.1) -> %Self.1;
+// CHECK:STDOUT:   fn[%self: @Op.2.%Self (%Self.1)](%other: @Op.2.%Self (%Self.1)) -> @Op.2.%Self (%Self.1);
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc23_14.3: %.7](@impl.2.%other.loc23_24.2: %C) {
@@ -207,7 +207,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %Self: %.6 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)]
 // CHECK:STDOUT:   %.2: type = ptr_type @Op.4.%Self (%Self.2) [symbolic = %.2 (constants.%.8)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[addr %self: %.8](%other: %Self.2);
+// CHECK:STDOUT:   fn[addr %self: @Op.4.%.2 (%.8)](%other: @Op.4.%Self (%Self.2));
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @TestOp(%a: %C, %b: %C) -> %return: %C {

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

@@ -227,13 +227,13 @@ fn TestLhsBad(a: D, b: C) -> bool {
 // CHECK:STDOUT: generic fn @Equal.2(constants.%Self: %.2) {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self](%other: %Self) -> bool;
+// CHECK:STDOUT:   fn[%self: @Equal.2.%Self (%Self)](%other: @Equal.2.%Self (%Self)) -> bool;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: generic fn @NotEqual.2(constants.%Self: %.2) {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self](%other: %Self) -> bool;
+// CHECK:STDOUT:   fn[%self: @NotEqual.2.%Self (%Self)](%other: @NotEqual.2.%Self (%Self)) -> bool;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @TestEqual(%a: %C, %b: %C) -> bool {
@@ -368,7 +368,7 @@ fn TestLhsBad(a: D, b: C) -> bool {
 // CHECK:STDOUT: generic fn @Equal(constants.%Self: %.4) {
 // CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self](%other: %Self) -> bool;
+// CHECK:STDOUT:   fn[%self: @Equal.%Self (%Self)](%other: @Equal.%Self (%Self)) -> bool;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @TestNotEqual(%a: %D, %b: %D) -> bool {
@@ -381,7 +381,7 @@ fn TestLhsBad(a: D, b: C) -> bool {
 // CHECK:STDOUT: generic fn @NotEqual(constants.%Self: %.4) {
 // CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self](%other: %Self) -> bool;
+// CHECK:STDOUT:   fn[%self: @NotEqual.%Self (%Self)](%other: @NotEqual.%Self (%Self)) -> bool;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_no_impl_for_args.carbon
@@ -540,13 +540,13 @@ fn TestLhsBad(a: D, b: C) -> bool {
 // CHECK:STDOUT: generic fn @Equal.2(constants.%Self: %.2) {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self](%other: %Self) -> bool;
+// CHECK:STDOUT:   fn[%self: @Equal.2.%Self (%Self)](%other: @Equal.2.%Self (%Self)) -> bool;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: generic fn @NotEqual.2(constants.%Self: %.2) {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self](%other: %Self) -> bool;
+// CHECK:STDOUT:   fn[%self: @NotEqual.2.%Self (%Self)](%other: @NotEqual.2.%Self (%Self)) -> bool;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @TestRhsBad(%a: %C, %b: %D) -> bool {

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

@@ -190,7 +190,7 @@ fn TestAddAssignNonRef(a: C, b: C) {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)]
 // CHECK:STDOUT:   %.2: type = ptr_type @Op.2.%Self (%Self.1) [symbolic = %.2 (constants.%.5)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[addr %self: %.5]();
+// CHECK:STDOUT:   fn[addr %self: @Op.2.%.2 (%.5)]();
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc19_14.3: %.3](@impl.2.%other.loc19_24.2: %C);
@@ -199,7 +199,7 @@ fn TestAddAssignNonRef(a: C, b: C) {
 // CHECK:STDOUT:   %Self: %.7 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)]
 // CHECK:STDOUT:   %.2: type = ptr_type @Op.4.%Self (%Self.2) [symbolic = %.2 (constants.%.8)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[addr %self: %.8](%other: %Self.2);
+// CHECK:STDOUT:   fn[addr %self: @Op.4.%.2 (%.8)](%other: @Op.4.%Self (%Self.2));
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @TestIncNonRef(%a: %C) {

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

@@ -195,7 +195,7 @@ fn TestRef(b: C) {
 // CHECK:STDOUT: generic fn @Op.1(constants.%Self.1: %.4) {
 // CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self.1]() -> %Self.1;
+// CHECK:STDOUT:   fn[%self: @Op.1.%Self (%Self.1)]() -> @Op.1.%Self (%Self.1);
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @TestBinary(%a: %C, %b: %C) -> %return: %C {
@@ -208,7 +208,7 @@ fn TestRef(b: C) {
 // CHECK:STDOUT: generic fn @Op.2(constants.%Self.2: %.7) {
 // CHECK:STDOUT:   %Self: %.7 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self.2](%other: %Self.2) -> %Self.2;
+// CHECK:STDOUT:   fn[%self: @Op.2.%Self (%Self.2)](%other: @Op.2.%Self (%Self.2)) -> @Op.2.%Self (%Self.2);
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @TestRef(%b: %C) {
@@ -230,13 +230,13 @@ fn TestRef(b: C) {
 // CHECK:STDOUT:   %Self: %.10 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.3)]
 // CHECK:STDOUT:   %.2: type = ptr_type @Op.3.%Self (%Self.3) [symbolic = %.2 (constants.%.11)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[addr %self: %.11](%other: %Self.3);
+// CHECK:STDOUT:   fn[addr %self: @Op.3.%.2 (%.11)](%other: @Op.3.%Self (%Self.3));
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: generic fn @Op.4(constants.%Self.4: %.14) {
 // CHECK:STDOUT:   %Self: %.14 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.4)]
 // CHECK:STDOUT:   %.2: type = ptr_type @Op.4.%Self (%Self.4) [symbolic = %.2 (constants.%.15)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[addr %self: %.15]();
+// CHECK:STDOUT:   fn[addr %self: @Op.4.%.2 (%.15)]();
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

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

@@ -204,7 +204,7 @@ fn TestAssign(b: D) {
 // CHECK:STDOUT: generic fn @Op.2(constants.%Self.1: %.2) {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self.1](%other: %Self.1) -> %Self.1;
+// CHECK:STDOUT:   fn[%self: @Op.2.%Self (%Self.1)](%other: @Op.2.%Self (%Self.1)) -> @Op.2.%Self (%Self.1);
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc20_14.3: %.6](@impl.2.%other.loc20_24.2: %C);
@@ -213,7 +213,7 @@ fn TestAssign(b: D) {
 // CHECK:STDOUT:   %Self: %.5 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)]
 // CHECK:STDOUT:   %.2: type = ptr_type @Op.4.%Self (%Self.2) [symbolic = %.2 (constants.%.7)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[addr %self: %.7](%other: %Self.2);
+// CHECK:STDOUT:   fn[addr %self: @Op.4.%.2 (%.7)](%other: @Op.4.%Self (%Self.2));
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Test(%a: %C, %b: %D) -> %return: %C {

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

@@ -113,7 +113,7 @@ fn TestOp() {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:   %.2: type = ptr_type @Op.2.%Self (%Self) [symbolic = %.2 (constants.%.5)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[addr %self: %.5]();
+// CHECK:STDOUT:   fn[addr %self: @Op.2.%.2 (%.5)]();
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @TestOp() {

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

@@ -195,7 +195,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT: generic fn @Op.2(constants.%Self.1: %.2) {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self.1](%other: %Self.1) -> %Self.1;
+// CHECK:STDOUT:   fn[%self: @Op.2.%Self (%Self.1)](%other: @Op.2.%Self (%Self.1)) -> @Op.2.%Self (%Self.1);
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc23_14.3: %.7](@impl.2.%other.loc23_24.2: %C) {
@@ -207,7 +207,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %Self: %.6 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)]
 // CHECK:STDOUT:   %.2: type = ptr_type @Op.4.%Self (%Self.2) [symbolic = %.2 (constants.%.8)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[addr %self: %.8](%other: %Self.2);
+// CHECK:STDOUT:   fn[addr %self: @Op.4.%.2 (%.8)](%other: @Op.4.%Self (%Self.2));
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @TestOp(%a: %C, %b: %C) -> %return: %C {

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

@@ -195,7 +195,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT: generic fn @Op.2(constants.%Self.1: %.2) {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self.1](%other: %Self.1) -> %Self.1;
+// CHECK:STDOUT:   fn[%self: @Op.2.%Self (%Self.1)](%other: @Op.2.%Self (%Self.1)) -> @Op.2.%Self (%Self.1);
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc23_14.3: %.7](@impl.2.%other.loc23_24.2: %C) {
@@ -207,7 +207,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %Self: %.6 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)]
 // CHECK:STDOUT:   %.2: type = ptr_type @Op.4.%Self (%Self.2) [symbolic = %.2 (constants.%.8)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[addr %self: %.8](%other: %Self.2);
+// CHECK:STDOUT:   fn[addr %self: @Op.4.%.2 (%.8)](%other: @Op.4.%Self (%Self.2));
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @TestOp(%a: %C, %b: %C) -> %return: %C {

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

@@ -195,7 +195,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT: generic fn @Op.2(constants.%Self.1: %.2) {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self.1](%other: %Self.1) -> %Self.1;
+// CHECK:STDOUT:   fn[%self: @Op.2.%Self (%Self.1)](%other: @Op.2.%Self (%Self.1)) -> @Op.2.%Self (%Self.1);
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc23_14.3: %.7](@impl.2.%other.loc23_24.2: %C) {
@@ -207,7 +207,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %Self: %.6 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)]
 // CHECK:STDOUT:   %.2: type = ptr_type @Op.4.%Self (%Self.2) [symbolic = %.2 (constants.%.8)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[addr %self: %.8](%other: %Self.2);
+// CHECK:STDOUT:   fn[addr %self: @Op.4.%.2 (%.8)](%other: @Op.4.%Self (%Self.2));
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @TestOp(%a: %C, %b: %C) -> %return: %C {

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

@@ -123,7 +123,7 @@ fn TestOp(a: C) -> C {
 // CHECK:STDOUT: generic fn @Op.2(constants.%Self: %.2) {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self]() -> %Self;
+// CHECK:STDOUT:   fn[%self: @Op.2.%Self (%Self)]() -> @Op.2.%Self (%Self);
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @TestOp(%a: %C) -> %return: %C {

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

@@ -302,25 +302,25 @@ fn TestGreaterEqual(a: D, b: D) -> bool {
 // CHECK:STDOUT: generic fn @Less.2(constants.%Self: %.2) {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self](%other: %Self) -> bool;
+// CHECK:STDOUT:   fn[%self: @Less.2.%Self (%Self)](%other: @Less.2.%Self (%Self)) -> bool;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: generic fn @LessOrEquivalent.2(constants.%Self: %.2) {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self](%other: %Self) -> bool;
+// CHECK:STDOUT:   fn[%self: @LessOrEquivalent.2.%Self (%Self)](%other: @LessOrEquivalent.2.%Self (%Self)) -> bool;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: generic fn @Greater.2(constants.%Self: %.2) {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self](%other: %Self) -> bool;
+// CHECK:STDOUT:   fn[%self: @Greater.2.%Self (%Self)](%other: @Greater.2.%Self (%Self)) -> bool;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: generic fn @GreaterOrEquivalent.2(constants.%Self: %.2) {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self](%other: %Self) -> bool;
+// CHECK:STDOUT:   fn[%self: @GreaterOrEquivalent.2.%Self (%Self)](%other: @GreaterOrEquivalent.2.%Self (%Self)) -> bool;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @TestLess(%a: %C, %b: %C) -> bool {
@@ -525,7 +525,7 @@ fn TestGreaterEqual(a: D, b: D) -> bool {
 // CHECK:STDOUT: generic fn @Less(constants.%Self: %.4) {
 // CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self](%other: %Self) -> bool;
+// CHECK:STDOUT:   fn[%self: @Less.%Self (%Self)](%other: @Less.%Self (%Self)) -> bool;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @TestLessEqual(%a: %D, %b: %D) -> bool {
@@ -538,7 +538,7 @@ fn TestGreaterEqual(a: D, b: D) -> bool {
 // CHECK:STDOUT: generic fn @LessOrEquivalent(constants.%Self: %.4) {
 // CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self](%other: %Self) -> bool;
+// CHECK:STDOUT:   fn[%self: @LessOrEquivalent.%Self (%Self)](%other: @LessOrEquivalent.%Self (%Self)) -> bool;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @TestGreater(%a: %D, %b: %D) -> bool {
@@ -551,7 +551,7 @@ fn TestGreaterEqual(a: D, b: D) -> bool {
 // CHECK:STDOUT: generic fn @Greater(constants.%Self: %.4) {
 // CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self](%other: %Self) -> bool;
+// CHECK:STDOUT:   fn[%self: @Greater.%Self (%Self)](%other: @Greater.%Self (%Self)) -> bool;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @TestGreaterEqual(%a: %D, %b: %D) -> bool {
@@ -564,6 +564,6 @@ fn TestGreaterEqual(a: D, b: D) -> bool {
 // CHECK:STDOUT: generic fn @GreaterOrEquivalent(constants.%Self: %.4) {
 // CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self](%other: %Self) -> bool;
+// CHECK:STDOUT:   fn[%self: @GreaterOrEquivalent.%Self (%Self)](%other: @GreaterOrEquivalent.%Self (%Self)) -> bool;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

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

@@ -195,7 +195,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT: generic fn @Op.2(constants.%Self.1: %.2) {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self.1](%other: %Self.1) -> %Self.1;
+// CHECK:STDOUT:   fn[%self: @Op.2.%Self (%Self.1)](%other: @Op.2.%Self (%Self.1)) -> @Op.2.%Self (%Self.1);
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc23_14.3: %.7](@impl.2.%other.loc23_24.2: %C) {
@@ -207,7 +207,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %Self: %.6 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)]
 // CHECK:STDOUT:   %.2: type = ptr_type @Op.4.%Self (%Self.2) [symbolic = %.2 (constants.%.8)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[addr %self: %.8](%other: %Self.2);
+// CHECK:STDOUT:   fn[addr %self: @Op.4.%.2 (%.8)](%other: @Op.4.%Self (%Self.2));
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @TestOp(%a: %C, %b: %C) -> %return: %C {

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

@@ -195,7 +195,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT: generic fn @Op.2(constants.%Self.1: %.2) {
 // CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.1)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: %Self.1](%other: %Self.1) -> %Self.1;
+// CHECK:STDOUT:   fn[%self: @Op.2.%Self (%Self.1)](%other: @Op.2.%Self (%Self.1)) -> @Op.2.%Self (%Self.1);
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc23_14.3: %.7](@impl.2.%other.loc23_24.2: %C) {
@@ -207,7 +207,7 @@ fn TestAssign(a: C*, b: C) {
 // CHECK:STDOUT:   %Self: %.6 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self.2)]
 // CHECK:STDOUT:   %.2: type = ptr_type @Op.4.%Self (%Self.2) [symbolic = %.2 (constants.%.8)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn[addr %self: %.8](%other: %Self.2);
+// CHECK:STDOUT:   fn[addr %self: @Op.4.%.2 (%.8)](%other: @Op.4.%Self (%Self.2));
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @TestOp(%a: %C, %b: %C) -> %return: %C {