ソースを参照

Check the orphan rule for impls (#6488)

The orphan rule is defined here:
https://docs.carbon-lang.dev/docs/design/generics/details.html#orphan-rule

**Orphan rule:** Some name from the type structure of an `impl`
declaration must be defined in the same library as the `impl`, that is
some name must be *local*.

Update tests that were running afoul of the orphan rule unintentionally.
Add tests that do violate the rule intentionally and test edge cases.
Dana Jansens 4 ヶ月 前
コミット
35d505a985

+ 1 - 0
toolchain/check/impl.cpp

@@ -20,6 +20,7 @@
 #include "toolchain/check/thunk.h"
 #include "toolchain/check/type.h"
 #include "toolchain/check/type_completion.h"
+#include "toolchain/check/type_structure.h"
 #include "toolchain/diagnostics/diagnostic_emitter.h"
 #include "toolchain/sem_ir/generic.h"
 #include "toolchain/sem_ir/ids.h"

+ 123 - 4
toolchain/check/impl_validation.cpp

@@ -17,6 +17,7 @@
 #include "toolchain/sem_ir/entity_with_params_base.h"
 #include "toolchain/sem_ir/ids.h"
 #include "toolchain/sem_ir/type_iterator.h"
+#include "toolchain/sem_ir/typed_insts.h"
 
 namespace Carbon::Check {
 
@@ -47,6 +48,35 @@ static auto GetIRId(Context& context, SemIR::InstId owning_inst_id)
   return GetCanonicalImportIRInst(context, owning_inst_id).ir_id();
 }
 
+// Returns if `owning_inst_id` is from the current file. This does not count an
+// api and impl file as the same file.
+static auto IsSameFile(Context& context, SemIR::InstId owning_inst_id) -> bool {
+  if (!owning_inst_id.has_value()) {
+    return false;
+  }
+  auto ir_id = GetCanonicalImportIRInst(context, owning_inst_id).ir_id();
+  return !ir_id.has_value();
+}
+
+// Returns if `owning_inst_id` is from the current library. This does count api
+// and impl files as the same library.
+static auto IsSameLibrary(Context& context, SemIR::InstId owning_inst_id)
+    -> bool {
+  if (!owning_inst_id.has_value()) {
+    return false;
+  }
+  auto ir_id = GetCanonicalImportIRInst(context, owning_inst_id).ir_id();
+  if (!ir_id.has_value()) {
+    return true;
+  }
+  if (const auto* api =
+          context.import_irs().Get(SemIR::ImportIRId::ApiForImpl).sem_ir) {
+    auto& ir = context.import_irs().Get(ir_id);
+    return ir.sem_ir == api;
+  }
+  return false;
+}
+
 static auto GetImplInfo(Context& context, SemIR::ImplId impl_id) -> ImplInfo {
   const auto& impl = context.impls().Get(impl_id);
   auto ir_id = GetIRId(context, impl.first_owning_decl_id);
@@ -78,15 +108,15 @@ static auto DiagnoseFinalImplNotInSameFileAsRootSelfTypeOrInterface(
   using Step = SemIR::TypeIterator::Step;
   CARBON_KIND_SWITCH(step.any) {
     case CARBON_KIND(Step::ClassStart start): {
-      auto inst_id = context.classes().Get(start.class_id).first_owning_decl_id;
-      if (!GetIRId(context, inst_id).has_value()) {
+      auto inst_id = context.classes().Get(start.class_id).definition_id;
+      if (IsSameFile(context, inst_id)) {
         self_type_same_file = true;
       }
       break;
     }
     case CARBON_KIND(Step::ClassStartOnly start): {
-      auto inst_id = context.classes().Get(start.class_id).first_owning_decl_id;
-      if (!GetIRId(context, inst_id).has_value()) {
+      auto inst_id = context.classes().Get(start.class_id).definition_id;
+      if (IsSameFile(context, inst_id)) {
         self_type_same_file = true;
       }
       break;
@@ -113,6 +143,93 @@ static auto DiagnoseFinalImplNotInSameFileAsRootSelfTypeOrInterface(
   return false;
 }
 
+static auto DiagnoseOrphanImpl(Context& context, const ImplInfo& impl,
+                               SemIR::ImportIRId interface_ir_id) -> bool {
+  // If the interface is defined in this file, then the impl is not an orphan.
+  if (!interface_ir_id.has_value()) {
+    return true;
+  }
+
+  // Look for a class in the self type, or the interface specific, that is from
+  // this file to show the impl is not an orphan.
+  auto type_iter = SemIR::TypeIterator(&context.sem_ir());
+  type_iter.Add(impl.self_id);
+  type_iter.Add(impl.interface);
+
+  for (auto done = false; !done;) {
+    auto step = type_iter.Next();
+
+    using Step = SemIR::TypeIterator::Step;
+    CARBON_KIND_SWITCH(step.any) {
+      case CARBON_KIND(Step::ClassStart start): {
+        auto inst_id = context.classes().Get(start.class_id).definition_id;
+        if (IsSameLibrary(context, inst_id)) {
+          return true;
+        }
+        break;
+      }
+      case CARBON_KIND(Step::ClassStartOnly start): {
+        auto inst_id = context.classes().Get(start.class_id).definition_id;
+        if (IsSameLibrary(context, inst_id)) {
+          return true;
+        }
+        break;
+      }
+      case CARBON_KIND(Step::ConcreteType type): {
+        // These are found in a specific when a `GenericClass`, a
+        // `GenericInterface` or a `GenericNamedConstraint` appears. The generic
+        // instruction itself is evaluated to a callable StructValue in the
+        // type, but the specific also contains the callable's type which is one
+        // of these.
+        CARBON_KIND_SWITCH(context.types().GetAsInst(type.type_id)) {
+          case CARBON_KIND(SemIR::GenericClassType class_type): {
+            auto class_id = class_type.class_id;
+            auto inst_id = context.classes().Get(class_id).definition_id;
+            if (IsSameLibrary(context, inst_id)) {
+              return true;
+            }
+            break;
+          }
+          case CARBON_KIND(SemIR::GenericInterfaceType interface_type): {
+            auto interface_id = interface_type.interface_id;
+            auto inst_id = context.interfaces().Get(interface_id).definition_id;
+            if (IsSameLibrary(context, inst_id)) {
+              return true;
+            }
+            break;
+          }
+          case CARBON_KIND(SemIR::GenericNamedConstraintType constraint_type): {
+            auto constraint_id = constraint_type.named_constraint_id;
+            auto inst_id =
+                context.named_constraints().Get(constraint_id).definition_id;
+            if (IsSameLibrary(context, inst_id)) {
+              return true;
+            }
+            break;
+          }
+          default:
+            break;
+        }
+        break;
+      }
+
+      case CARBON_KIND(Step::Done _): {
+        done = true;
+        break;
+      }
+
+      default:
+        break;
+    }
+  }
+
+  CARBON_DIAGNOSTIC(ImplIsOrphan, Error,
+                    "orphan `impl` found; something in the self-type or "
+                    "constraint must be defined in the same file");
+  context.emitter().Emit(impl.latest_decl_id, ImplIsOrphan);
+  return false;
+}
+
 // The type structure each non-final `impl` must differ from all other non-final
 // `impl` for the same interface visible from the file.
 //
@@ -249,6 +366,8 @@ static auto ValidateImplsForInterface(Context& context,
       // =======================================================================
       DiagnoseFinalImplNotInSameFileAsRootSelfTypeOrInterface(context, impl,
                                                               interface_ir_id);
+    } else if (impl.is_local) {
+      DiagnoseOrphanImpl(context, impl, interface_ir_id);
     }
   }
 

+ 49 - 45
toolchain/check/testdata/impl/impl_thunk_min_prelude.carbon

@@ -2,7 +2,7 @@
 // Exceptions. See /LICENSE for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
-// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/convert.carbon
+// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/int.carbon
 //
 // AUTOUPDATE
 // TIP: To test this file alone, run:
@@ -83,26 +83,19 @@ impl forall [T:! type, U:! Core.ImplicitAs(Wrap(T))] Wrap(T) as OpWith(U) {
 
 library "[[@TEST_NAME]]";
 
-fn IntLiteral() -> type = "int_literal.make_type";
-fn Int(size: IntLiteral()) -> type = "int.make_type_signed";
-
-impl IntLiteral() as Core.ImplicitAs(Int(32)) {
-  fn Convert[self: Self]() -> Int(32) = "int.convert_checked";
-}
-
 interface Add(T:! type) {
   fn Op(a: Self, b: T) -> Self;
 }
-impl forall [T:! Core.ImplicitAs(Int(32))] Int(32) as Add(T) {
+impl forall [T:! Core.ImplicitAs(i32)] i32 as Add(T) {
   fn Op(a: Self, b: Self) -> Self = "int.sadd";
 }
 
-fn Call() -> Int(32) {
-  let a: Int(32) = 1;
+fn Call() -> i32 {
+  let a: i32 = 1;
   // The conversion from 2 to IntLiteral here relies on having the
   // constant value available, so is only possible if the thunk is
   // inlined.
-  return Int(32).(Add(IntLiteral()).Op)
+  return i32.(Add(Core.IntLiteral()).Op)
   //@dump-sem-ir-begin
         (a, 2)
   //@dump-sem-ir-end
@@ -113,49 +106,60 @@ fn Call() -> Int(32) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT:   %int_32: Core.IntLiteral = int_value 32 [concrete]
-// CHECK:STDOUT:   %i32.builtin: type = int_type signed, %int_32 [concrete]
-// CHECK:STDOUT:   %ImplicitAs.type.873: type = facet_type <@ImplicitAs, @ImplicitAs(%i32.builtin)> [concrete]
-// CHECK:STDOUT:   %ImplicitAs.Convert.type.059: type = fn_type @ImplicitAs.Convert, @ImplicitAs(%i32.builtin) [concrete]
-// CHECK:STDOUT:   %ImplicitAs.impl_witness: <witness> = impl_witness file.%ImplicitAs.impl_witness_table [concrete]
-// CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert.type: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert [concrete]
-// CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type = struct_value () [concrete]
-// CHECK:STDOUT:   %ImplicitAs.facet: %ImplicitAs.type.873 = facet_value Core.IntLiteral, (%ImplicitAs.impl_witness) [concrete]
-// CHECK:STDOUT:   %.0f5: type = fn_type_with_self_type %ImplicitAs.Convert.type.059, %ImplicitAs.facet [concrete]
-// CHECK:STDOUT:   %i32.builtin.as.Add.impl.Op.type.615a7a.1: type = fn_type @i32.builtin.as.Add.impl.Op.loc15_35.1, @i32.builtin.as.Add.impl(%ImplicitAs.facet) [concrete]
-// CHECK:STDOUT:   %i32.builtin.as.Add.impl.Op.770876.1: %i32.builtin.as.Add.impl.Op.type.615a7a.1 = struct_value () [concrete]
+// CHECK:STDOUT:   %i32: type = class_type @Int, @Int(%int_32) [concrete]
+// CHECK:STDOUT:   %ImplicitAs.type.d14: type = facet_type <@ImplicitAs, @ImplicitAs(%i32)> [concrete]
+// CHECK:STDOUT:   %ImplicitAs.Convert.type.1b6: type = fn_type @ImplicitAs.Convert, @ImplicitAs(%i32) [concrete]
+// CHECK:STDOUT:   %To: Core.IntLiteral = symbolic_binding To, 0 [symbolic]
+// CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.412: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%To) [symbolic]
+// CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert.740: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.412 = struct_value () [symbolic]
+// CHECK:STDOUT:   %ImplicitAs.impl_witness.ec0: <witness> = impl_witness imports.%ImplicitAs.impl_witness_table.99e, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete]
+// CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.84b: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete]
+// CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert.6f0: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.84b = struct_value () [concrete]
+// CHECK:STDOUT:   %ImplicitAs.facet: %ImplicitAs.type.d14 = facet_value Core.IntLiteral, (%ImplicitAs.impl_witness.ec0) [concrete]
+// CHECK:STDOUT:   %.d28: type = fn_type_with_self_type %ImplicitAs.Convert.type.1b6, %ImplicitAs.facet [concrete]
+// CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn: <specific function> = specific_function %Core.IntLiteral.as.ImplicitAs.impl.Convert.6f0, @Core.IntLiteral.as.ImplicitAs.impl.Convert(%int_32) [concrete]
+// CHECK:STDOUT:   %i32.as.Add.impl.Op.type.3ea27d.1: type = fn_type @i32.as.Add.impl.Op.loc8_35.1, @i32.as.Add.impl(%ImplicitAs.facet) [concrete]
+// CHECK:STDOUT:   %i32.as.Add.impl.Op.f674ee.1: %i32.as.Add.impl.Op.type.3ea27d.1 = struct_value () [concrete]
 // CHECK:STDOUT:   %int_2.ecc: Core.IntLiteral = int_value 2 [concrete]
-// CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.e54: <bound method> = bound_method %int_2.ecc, %Core.IntLiteral.as.ImplicitAs.impl.Convert [concrete]
-// CHECK:STDOUT:   %int_2.5a1: %i32.builtin = int_value 2 [concrete]
-// CHECK:STDOUT:   %i32.builtin.as.Add.impl.Op.specific_fn.5e44fc.2: <specific function> = specific_function %i32.builtin.as.Add.impl.Op.770876.1, @i32.builtin.as.Add.impl.Op.loc15_35.1(%ImplicitAs.facet) [concrete]
+// CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.c08: <bound method> = bound_method %int_2.ecc, %Core.IntLiteral.as.ImplicitAs.impl.Convert.6f0 [concrete]
+// CHECK:STDOUT:   %bound_method.6f5: <bound method> = bound_method %int_2.ecc, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete]
+// CHECK:STDOUT:   %int_2.ef8: %i32 = int_value 2 [concrete]
+// CHECK:STDOUT:   %i32.as.Add.impl.Op.specific_fn.fbf325.2: <specific function> = specific_function %i32.as.Add.impl.Op.f674ee.1, @i32.as.Add.impl.Op.loc8_35.1(%ImplicitAs.facet) [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Core.import_ref.3e1: @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert.type (%Core.IntLiteral.as.ImplicitAs.impl.Convert.type.412) = import_ref Core//prelude/parts/int, loc{{\d+_\d+}}, loaded [symbolic = @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert (constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.740)]
+// CHECK:STDOUT:   %ImplicitAs.impl_witness_table.99e = impl_witness_table (%Core.import_ref.3e1), @Core.IntLiteral.as.ImplicitAs.impl [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: fn @Call() -> %i32.builtin {
+// CHECK:STDOUT: fn @Call() -> %i32 {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   <elided>
-// CHECK:STDOUT:   %a.ref: %i32.builtin = name_ref a, %a
+// CHECK:STDOUT:   %a.ref: %i32 = name_ref a, %a
 // CHECK:STDOUT:   %int_2: Core.IntLiteral = int_value 2 [concrete = constants.%int_2.ecc]
-// CHECK:STDOUT:   %ImplicitAs.facet.loc25_14.1: %ImplicitAs.type.873 = facet_value Core.IntLiteral, (constants.%ImplicitAs.impl_witness) [concrete = constants.%ImplicitAs.facet]
-// CHECK:STDOUT:   %.loc25_14.1: %ImplicitAs.type.873 = converted Core.IntLiteral, %ImplicitAs.facet.loc25_14.1 [concrete = constants.%ImplicitAs.facet]
-// CHECK:STDOUT:   %ImplicitAs.facet.loc25_14.2: %ImplicitAs.type.873 = facet_value Core.IntLiteral, (constants.%ImplicitAs.impl_witness) [concrete = constants.%ImplicitAs.facet]
-// CHECK:STDOUT:   %.loc25_14.2: %ImplicitAs.type.873 = converted Core.IntLiteral, %ImplicitAs.facet.loc25_14.2 [concrete = constants.%ImplicitAs.facet]
+// CHECK:STDOUT:   %ImplicitAs.facet.loc18_14.1: %ImplicitAs.type.d14 = facet_value Core.IntLiteral, (constants.%ImplicitAs.impl_witness.ec0) [concrete = constants.%ImplicitAs.facet]
+// CHECK:STDOUT:   %.loc18_14.1: %ImplicitAs.type.d14 = converted Core.IntLiteral, %ImplicitAs.facet.loc18_14.1 [concrete = constants.%ImplicitAs.facet]
+// CHECK:STDOUT:   %ImplicitAs.facet.loc18_14.2: %ImplicitAs.type.d14 = facet_value Core.IntLiteral, (constants.%ImplicitAs.impl_witness.ec0) [concrete = constants.%ImplicitAs.facet]
+// CHECK:STDOUT:   %.loc18_14.2: %ImplicitAs.type.d14 = converted Core.IntLiteral, %ImplicitAs.facet.loc18_14.2 [concrete = constants.%ImplicitAs.facet]
 // CHECK:STDOUT:   <elided>
-// CHECK:STDOUT:   %.loc25_14.3: %i32.builtin.as.Add.impl.Op.type.615a7a.1 = specific_constant @i32.builtin.as.Add.impl.%i32.builtin.as.Add.impl.Op.decl.loc15_35.1, @i32.builtin.as.Add.impl(constants.%ImplicitAs.facet) [concrete = constants.%i32.builtin.as.Add.impl.Op.770876.1]
-// CHECK:STDOUT:   %Op.ref.loc25: %i32.builtin.as.Add.impl.Op.type.615a7a.1 = name_ref Op, %.loc25_14.3 [concrete = constants.%i32.builtin.as.Add.impl.Op.770876.1]
-// CHECK:STDOUT:   %impl.elem0.loc25_14: %.0f5 = impl_witness_access constants.%ImplicitAs.impl_witness, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert]
-// CHECK:STDOUT:   %bound_method.loc25_14: <bound method> = bound_method %int_2, %impl.elem0.loc25_14 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.e54]
-// CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc25_14: init %i32.builtin = call %bound_method.loc25_14(%int_2) [concrete = constants.%int_2.5a1]
-// CHECK:STDOUT:   %.loc25_14.4: %i32.builtin = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc25_14 [concrete = constants.%int_2.5a1]
-// CHECK:STDOUT:   %.loc25_14.5: %i32.builtin = converted %int_2, %.loc25_14.4 [concrete = constants.%int_2.5a1]
-// CHECK:STDOUT:   %i32.builtin.as.Add.impl.Op.specific_fn: <specific function> = specific_function %Op.ref.loc25, @i32.builtin.as.Add.impl.Op.loc15_35.1(constants.%ImplicitAs.facet) [concrete = constants.%i32.builtin.as.Add.impl.Op.specific_fn.5e44fc.2]
-// CHECK:STDOUT:   %impl.elem0.loc25_13: %.0f5 = impl_witness_access constants.%ImplicitAs.impl_witness, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert]
-// CHECK:STDOUT:   %bound_method.loc25_13: <bound method> = bound_method %int_2, %impl.elem0.loc25_13 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.e54]
-// CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc25_13: init %i32.builtin = call %bound_method.loc25_13(%int_2) [concrete = constants.%int_2.5a1]
-// CHECK:STDOUT:   %.loc25_13.1: %i32.builtin = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc25_13 [concrete = constants.%int_2.5a1]
-// CHECK:STDOUT:   %.loc25_13.2: %i32.builtin = converted %int_2, %.loc25_13.1 [concrete = constants.%int_2.5a1]
-// CHECK:STDOUT:   %i32.builtin.as.Add.impl.Op.call: init %i32.builtin = call %i32.builtin.as.Add.impl.Op.specific_fn(%a.ref, %.loc25_13.2)
+// CHECK:STDOUT:   %.loc18_14.3: %i32.as.Add.impl.Op.type.3ea27d.1 = specific_constant @i32.as.Add.impl.%i32.as.Add.impl.Op.decl.loc8_35.1, @i32.as.Add.impl(constants.%ImplicitAs.facet) [concrete = constants.%i32.as.Add.impl.Op.f674ee.1]
+// CHECK:STDOUT:   %Op.ref.loc18: %i32.as.Add.impl.Op.type.3ea27d.1 = name_ref Op, %.loc18_14.3 [concrete = constants.%i32.as.Add.impl.Op.f674ee.1]
+// CHECK:STDOUT:   %impl.elem0.loc18_14: %.d28 = impl_witness_access constants.%ImplicitAs.impl_witness.ec0, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.6f0]
+// CHECK:STDOUT:   %bound_method.loc18_14.1: <bound method> = bound_method %int_2, %impl.elem0.loc18_14 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.c08]
+// CHECK:STDOUT:   %specific_fn.loc18_14: <specific function> = specific_function %impl.elem0.loc18_14, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn]
+// CHECK:STDOUT:   %bound_method.loc18_14.2: <bound method> = bound_method %int_2, %specific_fn.loc18_14 [concrete = constants.%bound_method.6f5]
+// CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc18_14: init %i32 = call %bound_method.loc18_14.2(%int_2) [concrete = constants.%int_2.ef8]
+// CHECK:STDOUT:   %.loc18_14.4: %i32 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc18_14 [concrete = constants.%int_2.ef8]
+// CHECK:STDOUT:   %.loc18_14.5: %i32 = converted %int_2, %.loc18_14.4 [concrete = constants.%int_2.ef8]
+// CHECK:STDOUT:   %i32.as.Add.impl.Op.specific_fn: <specific function> = specific_function %Op.ref.loc18, @i32.as.Add.impl.Op.loc8_35.1(constants.%ImplicitAs.facet) [concrete = constants.%i32.as.Add.impl.Op.specific_fn.fbf325.2]
+// CHECK:STDOUT:   %impl.elem0.loc18_13: %.d28 = impl_witness_access constants.%ImplicitAs.impl_witness.ec0, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.6f0]
+// CHECK:STDOUT:   %bound_method.loc18_13.1: <bound method> = bound_method %int_2, %impl.elem0.loc18_13 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.c08]
+// CHECK:STDOUT:   %specific_fn.loc18_13: <specific function> = specific_function %impl.elem0.loc18_13, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn]
+// CHECK:STDOUT:   %bound_method.loc18_13.2: <bound method> = bound_method %int_2, %specific_fn.loc18_13 [concrete = constants.%bound_method.6f5]
+// CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc18_13: init %i32 = call %bound_method.loc18_13.2(%int_2) [concrete = constants.%int_2.ef8]
+// CHECK:STDOUT:   %.loc18_13.1: %i32 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc18_13 [concrete = constants.%int_2.ef8]
+// CHECK:STDOUT:   %.loc18_13.2: %i32 = converted %int_2, %.loc18_13.1 [concrete = constants.%int_2.ef8]
+// CHECK:STDOUT:   %i32.as.Add.impl.Op.call: init %i32 = call %i32.as.Add.impl.Op.specific_fn(%a.ref, %.loc18_13.2)
 // CHECK:STDOUT:   <elided>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 48 - 22
toolchain/check/testdata/impl/import_generic.carbon

@@ -23,7 +23,9 @@ interface J(T:! type) {
 // --- basic_import_generic_interface.impl.carbon
 impl library "[[@TEST_NAME]]";
 
-impl {} as J({}) {}
+class C {}
+
+impl C as J({}) {}
 
 // --- basic_import_generic_constraint.carbon
 library "[[@TEST_NAME]]";
@@ -36,7 +38,9 @@ constraint J(T:! type) {
 // --- basic_import_generic_constraint.impl.carbon
 impl library "[[@TEST_NAME]]";
 
-impl {} as J({}) {}
+class C {}
+
+impl C as J({}) {}
 
 // --- import_generic.carbon
 
@@ -299,8 +303,9 @@ impl forall [T:! type] D as N(T*) {}
 // CHECK:STDOUT: --- basic_import_generic_interface.impl.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [concrete]
 // CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete]
-// CHECK:STDOUT:   %empty_struct: %empty_struct_type = struct_value () [concrete]
+// CHECK:STDOUT:   %complete_type.357: <witness> = complete_type_witness %empty_struct_type [concrete]
 // CHECK:STDOUT:   %J.type.2b8: type = generic_interface_type @J [concrete]
 // CHECK:STDOUT:   %J.generic: %J.type.2b8 = struct_value () [concrete]
 // CHECK:STDOUT:   %T: type = symbolic_binding T, 0 [symbolic]
@@ -310,11 +315,12 @@ impl forall [T:! type] D as N(T*) {}
 // CHECK:STDOUT:   %Self.213: %I.type.17e = symbolic_binding Self, 1 [symbolic]
 // CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 1, %Self.a17 [symbolic]
 // CHECK:STDOUT:   %require_complete: <witness> = require_complete_type %I.type.17e [symbolic]
+// CHECK:STDOUT:   %empty_struct: %empty_struct_type = struct_value () [concrete]
 // CHECK:STDOUT:   %J.type.457: type = facet_type <@J, @J(%empty_struct_type)> [concrete]
 // CHECK:STDOUT:   %Self.5cb: %J.type.457 = symbolic_binding Self, 1 [symbolic]
 // CHECK:STDOUT:   %I.type.399: type = facet_type <@I, @I(%empty_struct_type)> [concrete]
 // CHECK:STDOUT:   %Self.5c3: %I.type.399 = symbolic_binding Self, 1 [symbolic]
-// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %I.type.399 [concrete]
+// CHECK:STDOUT:   %complete_type.e4b: <witness> = complete_type_witness %I.type.399 [concrete]
 // CHECK:STDOUT:   %J.impl_witness: <witness> = impl_witness file.%J.impl_witness_table [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -335,18 +341,19 @@ impl forall [T:! type] D as N(T*) {}
 // CHECK:STDOUT:   package: <namespace> = namespace [concrete] {
 // CHECK:STDOUT:     .I = imports.%Main.I
 // CHECK:STDOUT:     .J = imports.%Main.J
+// CHECK:STDOUT:     .C = %C.decl
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %default.import.loc1_46.1 = import <none>
 // CHECK:STDOUT:   %default.import.loc1_46.2 = import <none>
-// CHECK:STDOUT:   impl_decl @empty_struct_type.as.J.impl [concrete] {} {
-// CHECK:STDOUT:     %.loc3_7.1: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct]
-// CHECK:STDOUT:     %.loc3_7.2: type = converted %.loc3_7.1, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
+// CHECK:STDOUT:   impl_decl @C.as.J.impl [concrete] {} {
+// CHECK:STDOUT:     %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C]
 // CHECK:STDOUT:     %J.ref: %J.type.2b8 = name_ref J, imports.%Main.J [concrete = constants.%J.generic]
-// CHECK:STDOUT:     %.loc3_15: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct]
-// CHECK:STDOUT:     %.loc3_16: type = converted %.loc3_15, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
+// CHECK:STDOUT:     %.loc5_14: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct]
+// CHECK:STDOUT:     %.loc5_15: type = converted %.loc5_14, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
 // CHECK:STDOUT:     %J.type: type = facet_type <@J, @J(constants.%empty_struct_type)> [concrete = constants.%J.type.457]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %J.impl_witness_table = impl_witness_table (), @empty_struct_type.as.J.impl [concrete]
+// CHECK:STDOUT:   %J.impl_witness_table = impl_witness_table (), @C.as.J.impl [concrete]
 // CHECK:STDOUT:   %J.impl_witness: <witness> = impl_witness %J.impl_witness_table [concrete = constants.%J.impl_witness]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -395,11 +402,19 @@ impl forall [T:! type] D as N(T*) {}
 // CHECK:STDOUT:   %I.type: type = facet_type <@I, @I(%T)> [symbolic = %I.type (constants.%I.type.17e)]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @empty_struct_type.as.J.impl: %.loc3_7.2 as %J.type {
+// CHECK:STDOUT: impl @C.as.J.impl: %C.ref as %J.type {
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   witness = file.%J.impl_witness
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness constants.%empty_struct_type [concrete = constants.%complete_type.357]
+// CHECK:STDOUT:   complete_type_witness = %complete_type
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: specific @J(constants.%T) {
 // CHECK:STDOUT:   %T => constants.%T
 // CHECK:STDOUT: }
@@ -427,7 +442,7 @@ impl forall [T:! type] D as N(T*) {}
 // CHECK:STDOUT:   %J.type => constants.%J.type.457
 // CHECK:STDOUT:   %Self => constants.%Self.5cb
 // CHECK:STDOUT:   %I.type => constants.%I.type.399
-// CHECK:STDOUT:   %require_complete => constants.%complete_type
+// CHECK:STDOUT:   %require_complete => constants.%complete_type.e4b
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @I(constants.%empty_struct_type) {
@@ -557,8 +572,9 @@ impl forall [T:! type] D as N(T*) {}
 // CHECK:STDOUT: --- basic_import_generic_constraint.impl.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [concrete]
 // CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete]
-// CHECK:STDOUT:   %empty_struct.a40: %empty_struct_type = struct_value () [concrete]
+// CHECK:STDOUT:   %complete_type.357: <witness> = complete_type_witness %empty_struct_type [concrete]
 // CHECK:STDOUT:   %J.type.267: type = generic_named_constaint_type @J [concrete]
 // CHECK:STDOUT:   %empty_struct.b6f: %J.type.267 = struct_value () [concrete]
 // CHECK:STDOUT:   %T: type = symbolic_binding T, 0 [symbolic]
@@ -568,11 +584,12 @@ impl forall [T:! type] D as N(T*) {}
 // CHECK:STDOUT:   %Self.213: %I.type.17e = symbolic_binding Self, 1 [symbolic]
 // CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 1, %Self.84c873.1 [symbolic]
 // CHECK:STDOUT:   %require_complete: <witness> = require_complete_type %I.type.17e [symbolic]
+// CHECK:STDOUT:   %empty_struct.a40: %empty_struct_type = struct_value () [concrete]
 // CHECK:STDOUT:   %J.type.b8d23b.2: type = facet_type <@J, @J(%empty_struct_type)> [concrete]
 // CHECK:STDOUT:   %I.type.399: type = facet_type <@I, @I(%empty_struct_type)> [concrete]
 // CHECK:STDOUT:   %Self.84c873.2: %J.type.b8d23b.2 = symbolic_binding Self, 1 [symbolic]
 // CHECK:STDOUT:   %Self.5c3: %I.type.399 = symbolic_binding Self, 1 [symbolic]
-// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %I.type.399 [concrete]
+// CHECK:STDOUT:   %complete_type.e4b: <witness> = complete_type_witness %I.type.399 [concrete]
 // CHECK:STDOUT:   %I.impl_witness: <witness> = impl_witness file.%I.impl_witness_table [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -593,18 +610,19 @@ impl forall [T:! type] D as N(T*) {}
 // CHECK:STDOUT:   package: <namespace> = namespace [concrete] {
 // CHECK:STDOUT:     .I = imports.%Main.I
 // CHECK:STDOUT:     .J = imports.%Main.J
+// CHECK:STDOUT:     .C = %C.decl
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %default.import.loc1_47.1 = import <none>
 // CHECK:STDOUT:   %default.import.loc1_47.2 = import <none>
-// CHECK:STDOUT:   impl_decl @empty_struct_type.as.I.impl [concrete] {} {
-// CHECK:STDOUT:     %.loc3_7.1: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct.a40]
-// CHECK:STDOUT:     %.loc3_7.2: type = converted %.loc3_7.1, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
+// CHECK:STDOUT:   impl_decl @C.as.I.impl [concrete] {} {
+// CHECK:STDOUT:     %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C]
 // CHECK:STDOUT:     %J.ref: %J.type.267 = name_ref J, imports.%Main.J [concrete = constants.%empty_struct.b6f]
-// CHECK:STDOUT:     %.loc3_15: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct.a40]
-// CHECK:STDOUT:     %.loc3_16: type = converted %.loc3_15, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
+// CHECK:STDOUT:     %.loc5_14: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct.a40]
+// CHECK:STDOUT:     %.loc5_15: type = converted %.loc5_14, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
 // CHECK:STDOUT:     %J.type: type = facet_type <@J, @J(constants.%empty_struct_type)> [concrete = constants.%J.type.b8d23b.2]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %I.impl_witness_table = impl_witness_table (), @empty_struct_type.as.I.impl [concrete]
+// CHECK:STDOUT:   %I.impl_witness_table = impl_witness_table (), @C.as.I.impl [concrete]
 // CHECK:STDOUT:   %I.impl_witness: <witness> = impl_witness %I.impl_witness_table [concrete = constants.%I.impl_witness]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -652,11 +670,19 @@ impl forall [T:! type] D as N(T*) {}
 // CHECK:STDOUT:   %I.type: type = facet_type <@I, @I(%T)> [symbolic = %I.type (constants.%I.type.17e)]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @empty_struct_type.as.I.impl: %.loc3_7.2 as %J.type {
+// CHECK:STDOUT: impl @C.as.I.impl: %C.ref as %J.type {
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   witness = file.%I.impl_witness
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness constants.%empty_struct_type [concrete = constants.%complete_type.357]
+// CHECK:STDOUT:   complete_type_witness = %complete_type
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: specific @J(constants.%T) {
 // CHECK:STDOUT:   %T => constants.%T
 // CHECK:STDOUT: }
@@ -684,7 +710,7 @@ impl forall [T:! type] D as N(T*) {}
 // CHECK:STDOUT:   %J.type => constants.%J.type.b8d23b.2
 // CHECK:STDOUT:   %Self => constants.%Self.84c873.2
 // CHECK:STDOUT:   %I.type => constants.%I.type.399
-// CHECK:STDOUT:   %require_complete => constants.%complete_type
+// CHECK:STDOUT:   %require_complete => constants.%complete_type.e4b
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @J.require0(constants.%empty_struct_type, constants.%Self.84c873.1) {

+ 84 - 66
toolchain/check/testdata/impl/import_self.carbon

@@ -26,11 +26,13 @@ library "[[@TEST_NAME]]";
 
 import library "a";
 
-impl () as Add {
-  fn Op[self: Self](other: Self) -> Self { return (); }
+class C { adapt (); }
+
+impl C as Add {
+  fn Op[self: Self](other: Self) -> Self { return () as C; }
 }
 
-fn F(x: (), y: ()) -> () {
+fn F(x: C, y: C) -> C {
   return x.(Add.Op)(y);
 }
 
@@ -120,8 +122,10 @@ fn F(x: (), y: ()) -> () {
 // CHECK:STDOUT: --- b.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [concrete]
 // CHECK:STDOUT:   %empty_tuple.type: type = tuple_type () [concrete]
-// CHECK:STDOUT:   %empty_tuple: %empty_tuple.type = tuple_value () [concrete]
+// CHECK:STDOUT:   %empty_tuple.af4: %empty_tuple.type = tuple_value () [concrete]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %empty_tuple.type [concrete]
 // CHECK:STDOUT:   %Add.type: type = facet_type <@Add> [concrete]
 // CHECK:STDOUT:   %Self: %Add.type = symbolic_binding Self, 0 [symbolic]
 // CHECK:STDOUT:   %Add.Op.type: type = fn_type @Add.Op [concrete]
@@ -129,15 +133,16 @@ fn F(x: (), y: ()) -> () {
 // CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self [symbolic]
 // CHECK:STDOUT:   %pattern_type.327: type = pattern_type %Self.binding.as_type [symbolic]
 // CHECK:STDOUT:   %Add.impl_witness: <witness> = impl_witness file.%Add.impl_witness_table [concrete]
-// CHECK:STDOUT:   %pattern_type.cb1: type = pattern_type %empty_tuple.type [concrete]
-// CHECK:STDOUT:   %empty_tuple.type.as.Add.impl.Op.type: type = fn_type @empty_tuple.type.as.Add.impl.Op [concrete]
-// CHECK:STDOUT:   %empty_tuple.type.as.Add.impl.Op: %empty_tuple.type.as.Add.impl.Op.type = struct_value () [concrete]
-// CHECK:STDOUT:   %Add.facet: %Add.type = facet_value %empty_tuple.type, (%Add.impl_witness) [concrete]
+// CHECK:STDOUT:   %pattern_type.c48: type = pattern_type %C [concrete]
+// CHECK:STDOUT:   %C.as.Add.impl.Op.type: type = fn_type @C.as.Add.impl.Op [concrete]
+// CHECK:STDOUT:   %C.as.Add.impl.Op: %C.as.Add.impl.Op.type = struct_value () [concrete]
+// CHECK:STDOUT:   %Add.facet: %Add.type = facet_value %C, (%Add.impl_witness) [concrete]
+// CHECK:STDOUT:   %empty_tuple.a69: %C = tuple_value () [concrete]
 // CHECK:STDOUT:   %F.type: type = fn_type @F [concrete]
 // CHECK:STDOUT:   %F: %F.type = struct_value () [concrete]
 // CHECK:STDOUT:   %Add.assoc_type: type = assoc_entity_type @Add [concrete]
 // CHECK:STDOUT:   %assoc0: %Add.assoc_type = assoc_entity element0, imports.%Main.import_ref.5a3 [concrete]
-// CHECK:STDOUT:   %.89b: type = fn_type_with_self_type %Add.Op.type, %Add.facet [concrete]
+// CHECK:STDOUT:   %.52c: type = fn_type_with_self_type %Add.Op.type, %Add.facet [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -157,41 +162,35 @@ fn F(x: (), y: ()) -> () {
 // CHECK:STDOUT:   package: <namespace> = namespace [concrete] {
 // CHECK:STDOUT:     .Add = imports.%Main.Add
 // CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .C = %C.decl
 // CHECK:STDOUT:     .F = %F.decl
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Core.import = import Core
 // CHECK:STDOUT:   %default.import = import <none>
-// CHECK:STDOUT:   impl_decl @empty_tuple.type.as.Add.impl [concrete] {} {
-// CHECK:STDOUT:     %.loc6_7.1: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple]
-// CHECK:STDOUT:     %.loc6_7.2: type = converted %.loc6_7.1, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
+// CHECK:STDOUT:   impl_decl @C.as.Add.impl [concrete] {} {
+// CHECK:STDOUT:     %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C]
 // CHECK:STDOUT:     %Add.ref: type = name_ref Add, imports.%Main.Add [concrete = constants.%Add.type]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Add.impl_witness_table = impl_witness_table (@empty_tuple.type.as.Add.impl.%empty_tuple.type.as.Add.impl.Op.decl), @empty_tuple.type.as.Add.impl [concrete]
+// CHECK:STDOUT:   %Add.impl_witness_table = impl_witness_table (@C.as.Add.impl.%C.as.Add.impl.Op.decl), @C.as.Add.impl [concrete]
 // CHECK:STDOUT:   %Add.impl_witness: <witness> = impl_witness %Add.impl_witness_table [concrete = constants.%Add.impl_witness]
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {
-// CHECK:STDOUT:     %x.patt: %pattern_type.cb1 = value_binding_pattern x [concrete]
-// CHECK:STDOUT:     %x.param_patt: %pattern_type.cb1 = value_param_pattern %x.patt, call_param0 [concrete]
-// CHECK:STDOUT:     %y.patt: %pattern_type.cb1 = value_binding_pattern y [concrete]
-// CHECK:STDOUT:     %y.param_patt: %pattern_type.cb1 = value_param_pattern %y.patt, call_param1 [concrete]
-// CHECK:STDOUT:     %return.patt: %pattern_type.cb1 = return_slot_pattern [concrete]
-// CHECK:STDOUT:     %return.param_patt: %pattern_type.cb1 = out_param_pattern %return.patt, call_param2 [concrete]
+// CHECK:STDOUT:     %x.patt: %pattern_type.c48 = value_binding_pattern x [concrete]
+// CHECK:STDOUT:     %x.param_patt: %pattern_type.c48 = value_param_pattern %x.patt, call_param0 [concrete]
+// CHECK:STDOUT:     %y.patt: %pattern_type.c48 = value_binding_pattern y [concrete]
+// CHECK:STDOUT:     %y.param_patt: %pattern_type.c48 = value_param_pattern %y.patt, call_param1 [concrete]
+// CHECK:STDOUT:     %return.patt: %pattern_type.c48 = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: %pattern_type.c48 = out_param_pattern %return.patt, call_param2 [concrete]
 // CHECK:STDOUT:   } {
-// CHECK:STDOUT:     %.loc10_24.1: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple]
-// CHECK:STDOUT:     %.loc10_24.2: type = converted %.loc10_24.1, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
-// CHECK:STDOUT:     %x.param: %empty_tuple.type = value_param call_param0
-// CHECK:STDOUT:     %.loc10_10.1: type = splice_block %.loc10_10.3 [concrete = constants.%empty_tuple.type] {
-// CHECK:STDOUT:       %.loc10_10.2: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple]
-// CHECK:STDOUT:       %.loc10_10.3: type = converted %.loc10_10.2, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
-// CHECK:STDOUT:     }
-// CHECK:STDOUT:     %x: %empty_tuple.type = value_binding x, %x.param
-// CHECK:STDOUT:     %y.param: %empty_tuple.type = value_param call_param1
-// CHECK:STDOUT:     %.loc10_17.1: type = splice_block %.loc10_17.3 [concrete = constants.%empty_tuple.type] {
-// CHECK:STDOUT:       %.loc10_17.2: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple]
-// CHECK:STDOUT:       %.loc10_17.3: type = converted %.loc10_17.2, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
-// CHECK:STDOUT:     }
-// CHECK:STDOUT:     %y: %empty_tuple.type = value_binding y, %y.param
-// CHECK:STDOUT:     %return.param: ref %empty_tuple.type = out_param call_param2
-// CHECK:STDOUT:     %return: ref %empty_tuple.type = return_slot %return.param
+// CHECK:STDOUT:     %C.ref.loc12_21: type = name_ref C, file.%C.decl [concrete = constants.%C]
+// CHECK:STDOUT:     %x.param: %C = value_param call_param0
+// CHECK:STDOUT:     %C.ref.loc12_9: type = name_ref C, file.%C.decl [concrete = constants.%C]
+// CHECK:STDOUT:     %x: %C = value_binding x, %x.param
+// CHECK:STDOUT:     %y.param: %C = value_param call_param1
+// CHECK:STDOUT:     %C.ref.loc12_15: type = name_ref C, file.%C.decl [concrete = constants.%C]
+// CHECK:STDOUT:     %y: %C = value_binding y, %y.param
+// CHECK:STDOUT:     %return.param: ref %C = out_param call_param2
+// CHECK:STDOUT:     %return: ref %C = return_slot %return.param
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -204,31 +203,43 @@ fn F(x: (), y: ()) -> () {
 // CHECK:STDOUT: !requires:
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @empty_tuple.type.as.Add.impl: %.loc6_7.2 as %Add.ref {
-// CHECK:STDOUT:   %empty_tuple.type.as.Add.impl.Op.decl: %empty_tuple.type.as.Add.impl.Op.type = fn_decl @empty_tuple.type.as.Add.impl.Op [concrete = constants.%empty_tuple.type.as.Add.impl.Op] {
-// CHECK:STDOUT:     %self.patt: %pattern_type.cb1 = value_binding_pattern self [concrete]
-// CHECK:STDOUT:     %self.param_patt: %pattern_type.cb1 = value_param_pattern %self.patt, call_param0 [concrete]
-// CHECK:STDOUT:     %other.patt: %pattern_type.cb1 = value_binding_pattern other [concrete]
-// CHECK:STDOUT:     %other.param_patt: %pattern_type.cb1 = value_param_pattern %other.patt, call_param1 [concrete]
-// CHECK:STDOUT:     %return.patt: %pattern_type.cb1 = return_slot_pattern [concrete]
-// CHECK:STDOUT:     %return.param_patt: %pattern_type.cb1 = out_param_pattern %return.patt, call_param2 [concrete]
+// CHECK:STDOUT: impl @C.as.Add.impl: %C.ref as %Add.ref {
+// CHECK:STDOUT:   %C.as.Add.impl.Op.decl: %C.as.Add.impl.Op.type = fn_decl @C.as.Add.impl.Op [concrete = constants.%C.as.Add.impl.Op] {
+// CHECK:STDOUT:     %self.patt: %pattern_type.c48 = value_binding_pattern self [concrete]
+// CHECK:STDOUT:     %self.param_patt: %pattern_type.c48 = value_param_pattern %self.patt, call_param0 [concrete]
+// CHECK:STDOUT:     %other.patt: %pattern_type.c48 = value_binding_pattern other [concrete]
+// CHECK:STDOUT:     %other.param_patt: %pattern_type.c48 = value_param_pattern %other.patt, call_param1 [concrete]
+// CHECK:STDOUT:     %return.patt: %pattern_type.c48 = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: %pattern_type.c48 = out_param_pattern %return.patt, call_param2 [concrete]
 // CHECK:STDOUT:   } {
-// CHECK:STDOUT:     %Self.ref.loc7_37: type = name_ref Self, @empty_tuple.type.as.Add.impl.%.loc6_7.2 [concrete = constants.%empty_tuple.type]
-// CHECK:STDOUT:     %self.param: %empty_tuple.type = value_param call_param0
-// CHECK:STDOUT:     %Self.ref.loc7_15: type = name_ref Self, @empty_tuple.type.as.Add.impl.%.loc6_7.2 [concrete = constants.%empty_tuple.type]
-// CHECK:STDOUT:     %self: %empty_tuple.type = value_binding self, %self.param
-// CHECK:STDOUT:     %other.param: %empty_tuple.type = value_param call_param1
-// CHECK:STDOUT:     %Self.ref.loc7_28: type = name_ref Self, @empty_tuple.type.as.Add.impl.%.loc6_7.2 [concrete = constants.%empty_tuple.type]
-// CHECK:STDOUT:     %other: %empty_tuple.type = value_binding other, %other.param
-// CHECK:STDOUT:     %return.param: ref %empty_tuple.type = out_param call_param2
-// CHECK:STDOUT:     %return: ref %empty_tuple.type = return_slot %return.param
+// CHECK:STDOUT:     %Self.ref.loc9_37: type = name_ref Self, @C.as.Add.impl.%C.ref [concrete = constants.%C]
+// CHECK:STDOUT:     %self.param: %C = value_param call_param0
+// CHECK:STDOUT:     %Self.ref.loc9_15: type = name_ref Self, @C.as.Add.impl.%C.ref [concrete = constants.%C]
+// CHECK:STDOUT:     %self: %C = value_binding self, %self.param
+// CHECK:STDOUT:     %other.param: %C = value_param call_param1
+// CHECK:STDOUT:     %Self.ref.loc9_28: type = name_ref Self, @C.as.Add.impl.%C.ref [concrete = constants.%C]
+// CHECK:STDOUT:     %other: %C = value_binding other, %other.param
+// CHECK:STDOUT:     %return.param: ref %C = out_param call_param2
+// CHECK:STDOUT:     %return: ref %C = return_slot %return.param
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Op = %empty_tuple.type.as.Add.impl.Op.decl
+// CHECK:STDOUT:   .Op = %C.as.Add.impl.Op.decl
+// CHECK:STDOUT:   .C = <poisoned>
 // CHECK:STDOUT:   witness = file.%Add.impl_witness
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT:   %.loc6_18: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple.af4]
+// CHECK:STDOUT:   %.loc6_19: type = converted %.loc6_18, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
+// CHECK:STDOUT:   adapt_decl %.loc6_19 [concrete]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness constants.%empty_tuple.type [concrete = constants.%complete_type]
+// CHECK:STDOUT:   complete_type_witness = %complete_type
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: generic fn @Add.Op(imports.%Main.import_ref.9bc: %Add.type) [from "a.carbon"] {
 // CHECK:STDOUT:   %Self: %Add.type = symbolic_binding Self, 0 [symbolic = %Self (constants.%Self)]
 // CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
@@ -237,24 +248,31 @@ fn F(x: (), y: ()) -> () {
 // CHECK:STDOUT:   fn;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: fn @empty_tuple.type.as.Add.impl.Op(%self.param: %empty_tuple.type, %other.param: %empty_tuple.type) -> %empty_tuple.type {
+// CHECK:STDOUT: fn @C.as.Add.impl.Op(%self.param: %C, %other.param: %C) -> %C {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %.loc7_52.1: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple]
-// CHECK:STDOUT:   %.loc7_52.2: init %empty_tuple.type = tuple_init () to %return [concrete = constants.%empty_tuple]
-// CHECK:STDOUT:   %.loc7_53: init %empty_tuple.type = converted %.loc7_52.1, %.loc7_52.2 [concrete = constants.%empty_tuple]
-// CHECK:STDOUT:   return %.loc7_53 to %return
+// CHECK:STDOUT:   %.loc9_52: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple.af4]
+// CHECK:STDOUT:   %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C]
+// CHECK:STDOUT:   %empty_tuple: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple.af4]
+// CHECK:STDOUT:   %.loc9_54.1: %C = as_compatible %empty_tuple [concrete = constants.%empty_tuple.a69]
+// CHECK:STDOUT:   %.loc9_54.2: %C = converted %.loc9_52, %.loc9_54.1 [concrete = constants.%empty_tuple.a69]
+// CHECK:STDOUT:   %.loc9_58.1: %empty_tuple.type = as_compatible %.loc9_54.2 [concrete = constants.%empty_tuple.af4]
+// CHECK:STDOUT:   %.loc9_58.2: ref %empty_tuple.type = as_compatible %return
+// CHECK:STDOUT:   %.loc9_58.3: init %empty_tuple.type = tuple_init () to %.loc9_58.2 [concrete = constants.%empty_tuple.af4]
+// CHECK:STDOUT:   %.loc9_58.4: init %C = as_compatible %.loc9_58.3 [concrete = constants.%empty_tuple.a69]
+// CHECK:STDOUT:   %.loc9_58.5: init %C = converted %.loc9_54.2, %.loc9_58.4 [concrete = constants.%empty_tuple.a69]
+// CHECK:STDOUT:   return %.loc9_58.5 to %return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: fn @F(%x.param: %empty_tuple.type, %y.param: %empty_tuple.type) -> %empty_tuple.type {
+// CHECK:STDOUT: fn @F(%x.param: %C, %y.param: %C) -> %C {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %x.ref: %empty_tuple.type = name_ref x, %x
+// CHECK:STDOUT:   %x.ref: %C = name_ref x, %x
 // CHECK:STDOUT:   %Add.ref: type = name_ref Add, imports.%Main.Add [concrete = constants.%Add.type]
 // CHECK:STDOUT:   %Op.ref: %Add.assoc_type = name_ref Op, imports.%Main.import_ref.f99 [concrete = constants.%assoc0]
-// CHECK:STDOUT:   %impl.elem0: %.89b = impl_witness_access constants.%Add.impl_witness, element0 [concrete = constants.%empty_tuple.type.as.Add.impl.Op]
+// CHECK:STDOUT:   %impl.elem0: %.52c = impl_witness_access constants.%Add.impl_witness, element0 [concrete = constants.%C.as.Add.impl.Op]
 // CHECK:STDOUT:   %bound_method: <bound method> = bound_method %x.ref, %impl.elem0
-// CHECK:STDOUT:   %y.ref: %empty_tuple.type = name_ref y, %y
-// CHECK:STDOUT:   %empty_tuple.type.as.Add.impl.Op.call: init %empty_tuple.type = call %bound_method(%x.ref, %y.ref)
-// CHECK:STDOUT:   return %empty_tuple.type.as.Add.impl.Op.call to %return
+// CHECK:STDOUT:   %y.ref: %C = name_ref y, %y
+// CHECK:STDOUT:   %C.as.Add.impl.Op.call: init %C = call %bound_method(%x.ref, %y.ref)
+// CHECK:STDOUT:   return %C.as.Add.impl.Op.call to %return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @Add.Op(constants.%Self) {
@@ -265,7 +283,7 @@ fn F(x: (), y: ()) -> () {
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @Add.Op(constants.%Add.facet) {
 // CHECK:STDOUT:   %Self => constants.%Add.facet
-// CHECK:STDOUT:   %Self.binding.as_type => constants.%empty_tuple.type
-// CHECK:STDOUT:   %pattern_type => constants.%pattern_type.cb1
+// CHECK:STDOUT:   %Self.binding.as_type => constants.%C
+// CHECK:STDOUT:   %pattern_type => constants.%pattern_type.c48
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 42 - 15
toolchain/check/testdata/impl/lookup/impl_overlap.carbon

@@ -51,10 +51,21 @@ library "[[@TEST_NAME]]";
 
 interface Z {}
 
+class C {}
+
+final impl C as Z {}
+
+// --- final_impl_with_interface_concrete_self_same_file_defined_after.carbon
+library "[[@TEST_NAME]]";
+
+interface Z {}
+
 class C;
 
 final impl C as Z {}
 
+class C {}
+
 // --- final_impl_with_interface_concrete_self_from_other_file.carbon
 library "[[@TEST_NAME]]";
 
@@ -96,7 +107,7 @@ final impl forall [T:! type] T as Z(T) {}
 // CHECK:STDERR:
 final impl forall [T:! type] T as Z(()) {}
 
-class C;
+class C {}
 
 // The final impl here overlaps with the first final impl above, but is not in
 // a match_first.
@@ -115,7 +126,7 @@ library "[[@TEST_NAME]]";
 
 import library "interface_z";
 
-class C;
+class C {}
 
 final impl C as Z(()) {}
 
@@ -148,7 +159,7 @@ library "[[@TEST_NAME]]";
 
 import library "interface_z";
 
-class C;
+class C {}
 
 // Two final impls for C as Z, but they are not overlapping so they are allowed
 // outside of match_first.
@@ -160,7 +171,7 @@ library "[[@TEST_NAME]]";
 
 import library "interface_z";
 
-class C(T:! type);
+class C(T:! type) {}
 
 // Can provide a specialized final blanket impl for a type defined in the same
 // file.
@@ -171,7 +182,7 @@ library "[[@TEST_NAME]]";
 
 import library "interface_z_with_impl";
 
-class C;
+class C {}
 
 // Can't write a final impl in both the interface's file and the root self
 // type's file (when they are different files).
@@ -191,7 +202,7 @@ library "[[@TEST_NAME]]";
 
 import library "interface_z_with_impl";
 
-class C;
+class C {}
 
 // This final impl is overlapped by a final impl in the interface file, and you
 // can't write a final impl in two different files.
@@ -211,7 +222,7 @@ library "[[@TEST_NAME]]";
 
 import library "interface_z_with_impl";
 
-class C;
+class C {}
 
 // This non-final impl is subsumed by a final impl in the interface file.
 //
@@ -225,7 +236,7 @@ class C;
 // CHECK:STDERR:
 impl C as Z(C) {}
 
-// --- fail_final_different_file_from_self_and_interface.carbon
+// --- fail_final_root_self_type_not_defined.carbon
 library "[[@TEST_NAME]]";
 
 import library "interface_z";
@@ -233,6 +244,22 @@ import library "type_d";
 
 class C;
 
+// The root type must be defined in the same library, not just declared.
+//
+// CHECK:STDERR: fail_final_root_self_type_not_defined.carbon:[[@LINE+4]]:1: error: `final impl` found in file that does not contain the root self type nor the interface definition [FinalImplInvalidFile]
+// CHECK:STDERR: final impl C as Z(()) {}
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR:
+final impl C as Z(()) {}
+
+// --- fail_final_different_file_from_self_and_interface.carbon
+library "[[@TEST_NAME]]";
+
+import library "interface_z";
+import library "type_d";
+
+class C {}
+
 // Can't make a final impl that is not in the same file as the self type nor
 // the interface.
 //
@@ -247,7 +274,7 @@ library "[[@TEST_NAME]]";
 
 import library "interface_z";
 
-class C;
+class C {}
 
 // Can't make a final impl that is not in the same file as the self type nor
 // the interface.
@@ -295,7 +322,7 @@ library "[[@TEST_NAME]]";
 
 interface Z(T:! type) {}
 
-class C;
+class C {}
 
 final impl C as Z(C) {}
 
@@ -313,7 +340,7 @@ library "[[@TEST_NAME]]";
 
 interface Z(T:! type) {}
 
-class C;
+class C {}
 
 final impl forall [T:! type] T as Z(T) {}
 
@@ -353,8 +380,8 @@ library "[[@TEST_NAME]]";
 
 interface Z {}
 
-class C;
-class D;
+class C {}
+class D {}
 
 impl C as Z {}
 impl D as Z {}
@@ -366,11 +393,11 @@ interface Z(T:! type) {}
 
 impl forall [T:! type] T as Z(T) {}
 
-class C;
+class C {}
 // Partially overlaps the blanket impl, which is fine.
 final impl C as Z(C) {}
 
-class D;
+class D {}
 // Partially overlaps the blanket impl, which is fine.
 impl D as Z(D) {}
 

+ 216 - 0
toolchain/check/testdata/impl/orphan.carbon

@@ -0,0 +1,216 @@
+// 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-FILE: toolchain/testing/testdata/min_prelude/none.carbon
+//
+// AUTOUPDATE
+// TIP: To test this file alone, run:
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/impl/orphan.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/impl/orphan.carbon
+
+// --- imports.carbon
+library "[[@TEST_NAME]]";
+
+class ImportedC {}
+class ImportedD(T:! type) {}
+
+interface ImportedY {}
+interface ImportedZ(T:! type) {}
+
+constraint ImportedN(T:! type) {}
+
+class ImportedAnyParam[T:! type](X:! T) {}
+
+// --- fail_class_definition_missing.carbon
+library "[[@TEST_NAME]]";
+
+import library "imports";
+
+class C;
+
+// CHECK:STDERR: fail_class_definition_missing.carbon:[[@LINE+4]]:1: error: orphan `impl` found; something in the self-type or constraint must be defined in the same file [ImplIsOrphan]
+// CHECK:STDERR: impl C as ImportedY {}
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR:
+impl C as ImportedY {}
+
+// --- fail_class_definition_missing_for_self_specific.carbon
+library "[[@TEST_NAME]]";
+
+import library "imports";
+
+class C;
+
+// CHECK:STDERR: fail_class_definition_missing_for_self_specific.carbon:[[@LINE+4]]:1: error: orphan `impl` found; something in the self-type or constraint must be defined in the same file [ImplIsOrphan]
+// CHECK:STDERR: impl ImportedD(C) as ImportedY {}
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR:
+impl ImportedD(C) as ImportedY {}
+
+// --- fail_class_definition_missing_for_interface_specific.carbon
+library "[[@TEST_NAME]]";
+
+import library "imports";
+
+class C;
+
+// CHECK:STDERR: fail_class_definition_missing_for_interface_specific.carbon:[[@LINE+4]]:1: error: orphan `impl` found; something in the self-type or constraint must be defined in the same file [ImplIsOrphan]
+// CHECK:STDERR: impl ImportedC as ImportedZ(C) {}
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR:
+impl ImportedC as ImportedZ(C) {}
+
+// --- fail_imported_class.carbon
+library "[[@TEST_NAME]]";
+
+import library "imports";
+
+// CHECK:STDERR: fail_imported_class.carbon:[[@LINE+4]]:1: error: orphan `impl` found; something in the self-type or constraint must be defined in the same file [ImplIsOrphan]
+// CHECK:STDERR: impl ImportedC as ImportedY {}
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR:
+impl ImportedC as ImportedY {}
+
+// --- fail_imported_class_for_self_specific.carbon
+library "[[@TEST_NAME]]";
+
+import library "imports";
+
+// CHECK:STDERR: fail_imported_class_for_self_specific.carbon:[[@LINE+4]]:1: error: orphan `impl` found; something in the self-type or constraint must be defined in the same file [ImplIsOrphan]
+// CHECK:STDERR: impl ImportedD(ImportedC) as ImportedY {}
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR:
+impl ImportedD(ImportedC) as ImportedY {}
+
+// --- fail_imported_class_for_interface_specific.carbon
+library "[[@TEST_NAME]]";
+
+import library "imports";
+
+// CHECK:STDERR: fail_imported_class_for_interface_specific.carbon:[[@LINE+4]]:1: error: orphan `impl` found; something in the self-type or constraint must be defined in the same file [ImplIsOrphan]
+// CHECK:STDERR: impl ImportedC as ImportedZ(ImportedC) {}
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR:
+impl ImportedC as ImportedZ(ImportedC) {}
+
+// --- class_definition_after.carbon
+library "[[@TEST_NAME]]";
+
+import library "imports";
+
+class C;
+
+impl C as ImportedY {}
+
+class C {}
+
+// --- class_definition_after_for_self_specific.carbon
+library "[[@TEST_NAME]]";
+
+import library "imports";
+
+class C;
+
+impl ImportedD(C) as ImportedY {}
+
+class C {}
+
+// --- class_definition_after_for_interface_specific.carbon
+library "[[@TEST_NAME]]";
+
+import library "imports";
+
+class C;
+
+impl ImportedC as ImportedZ(C) {}
+
+class C {}
+
+// --- class_definition_before.carbon
+library "[[@TEST_NAME]]";
+
+import library "imports";
+
+class C {}
+
+impl C as ImportedY {}
+
+// --- class_definition_before_for_self_specific.carbon
+library "[[@TEST_NAME]]";
+
+import library "imports";
+
+class C {}
+
+impl ImportedD(C) as ImportedY {}
+
+// --- class_definition_before_for_interface_specific.carbon
+library "[[@TEST_NAME]]";
+
+import library "imports";
+
+class C {}
+
+impl ImportedC as ImportedZ(C) {}
+
+// --- fail_generic_class_from_import.carbon
+library "[[@TEST_NAME]]";
+
+import library "imports";
+
+// CHECK:STDERR: fail_generic_class_from_import.carbon:[[@LINE+4]]:1: error: orphan `impl` found; something in the self-type or constraint must be defined in the same file [ImplIsOrphan]
+// CHECK:STDERR: impl ImportedAnyParam(ImportedD) as ImportedY {}
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR:
+impl ImportedAnyParam(ImportedD) as ImportedY {}
+
+// --- generic_class.carbon
+library "[[@TEST_NAME]]";
+
+import library "imports";
+
+class D(T:! type) {}
+
+impl ImportedAnyParam(D) as ImportedY {}
+
+// --- fail_generic_interface_from_import.carbon
+library "[[@TEST_NAME]]";
+
+import library "imports";
+
+// CHECK:STDERR: fail_generic_interface_from_import.carbon:[[@LINE+4]]:1: error: orphan `impl` found; something in the self-type or constraint must be defined in the same file [ImplIsOrphan]
+// CHECK:STDERR: impl ImportedAnyParam(ImportedZ) as ImportedY {}
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR:
+impl ImportedAnyParam(ImportedZ) as ImportedY {}
+
+// --- generic_interface.carbon
+library "[[@TEST_NAME]]";
+
+import library "imports";
+
+interface Z(T:! type) {}
+
+impl ImportedAnyParam(Z) as ImportedY {}
+
+// --- fail_generic_named_constraint_from_import.carbon
+library "[[@TEST_NAME]]";
+
+import library "imports";
+
+// CHECK:STDERR: fail_generic_named_constraint_from_import.carbon:[[@LINE+4]]:1: error: orphan `impl` found; something in the self-type or constraint must be defined in the same file [ImplIsOrphan]
+// CHECK:STDERR: impl ImportedAnyParam(ImportedN) as ImportedY {}
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR:
+impl ImportedAnyParam(ImportedN) as ImportedY {}
+
+// --- generic_named_constraint.carbon
+library "[[@TEST_NAME]]";
+
+import library "imports";
+
+constraint N(T:! type) {}
+
+impl ImportedAnyParam(N) as ImportedY {}

+ 106 - 52
toolchain/check/testdata/operators/overloaded/index.carbon

@@ -2,7 +2,7 @@
 // Exceptions. See /LICENSE for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
-// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/none.carbon
+// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/convert.carbon
 // TODO: Add ranges and switch to "--dump-sem-ir-ranges=only".
 // EXTRA-ARGS: --dump-sem-ir-ranges=if-present
 //
@@ -34,7 +34,7 @@ fn F() { 0[1]; }
 
 library "[[@TEST_NAME]]";
 
-// CHECK:STDERR: fail_missing_index_with.carbon:[[@LINE+4]]:10: error: `Core.IndexWith` implicitly referenced here, but package `Core` not found [CoreNotFound]
+// CHECK:STDERR: fail_missing_index_with.carbon:[[@LINE+4]]:10: error: name `Core.IndexWith` implicitly referenced here, but not found [CoreNameNotFound]
 // CHECK:STDERR: fn F() { 0[1]; }
 // CHECK:STDERR:          ^~~~
 // CHECK:STDERR:
@@ -55,21 +55,25 @@ library "[[@TEST_NAME]]";
 
 import Core library "core_wrong_arg_count";
 
-impl () as Core.IndexWith((), ()) {
+class C {}
+
+impl C as Core.IndexWith((), ()) {
   fn At[self: Self](subscript: ()) -> () {
     return ();
   }
 }
 
-// CHECK:STDERR: fail_wrong_arg_count.carbon:[[@LINE+8]]:10: error: 1 argument passed to generic interface expecting 2 arguments [CallArgCountMismatch]
-// CHECK:STDERR: fn F() { ()[()]; }
-// CHECK:STDERR:          ^~~~~~
-// CHECK:STDERR: fail_wrong_arg_count.carbon:[[@LINE-11]]:1: in import [InImport]
-// CHECK:STDERR: core_wrong_arg_count.carbon:4:1: note: calling generic interface declared here [InCallToEntity]
-// CHECK:STDERR: interface IndexWith(SubscriptType:! type, ElementType:! type) {
-// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// CHECK:STDERR:
-fn F() { ()[()]; }
+fn F() {
+  let c: C = {};
+  // CHECK:STDERR: fail_wrong_arg_count.carbon:[[@LINE+7]]:3: error: 1 argument passed to generic interface expecting 2 arguments [CallArgCountMismatch]
+  // CHECK:STDERR:   c[()];
+  // CHECK:STDERR:   ^~~~~
+  // CHECK:STDERR: core_wrong_arg_count.carbon:4:1: note: calling generic interface declared here [InCallToEntity]
+  // CHECK:STDERR: interface IndexWith(SubscriptType:! type, ElementType:! type) {
+  // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  // CHECK:STDERR:
+  c[()];
+}
 
 // CHECK:STDOUT: --- core_wrong_index_with.carbon
 // CHECK:STDOUT:
@@ -109,7 +113,9 @@ fn F() { ()[()]; }
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [concrete] {
 // CHECK:STDOUT:     .IndexWith = %Core.IndexWith
+// CHECK:STDOUT:     import Core//prelude
 // CHECK:STDOUT:     import Core//core_wrong_index_with
+// CHECK:STDOUT:     import Core//prelude/...
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Core.IndexWith: type = import_ref Core//core_wrong_index_with, IndexWith, loaded [concrete = constants.%IndexWith]
 // CHECK:STDOUT:   %Core.import_ref.8f2: <witness> = import_ref Core//core_wrong_index_with, loc{{\d+_\d+}}, loaded [concrete = constants.%complete_type]
@@ -148,10 +154,20 @@ fn F() { ()[()]; }
 // CHECK:STDOUT:   %int_1: Core.IntLiteral = int_value 1 [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [concrete] {
+// CHECK:STDOUT:     .IndexWith = <poisoned>
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/...
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [concrete] {
+// CHECK:STDOUT:     .Core = imports.%Core
 // CHECK:STDOUT:     .F = %F.decl
 // CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {} {}
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -281,8 +297,10 @@ fn F() { ()[()]; }
 // CHECK:STDOUT: --- fail_wrong_arg_count.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [concrete]
+// CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete]
 // CHECK:STDOUT:   %empty_tuple.type: type = tuple_type () [concrete]
-// CHECK:STDOUT:   %empty_tuple: %empty_tuple.type = tuple_value () [concrete]
 // CHECK:STDOUT:   %IndexWith.type.504: type = generic_interface_type @IndexWith [concrete]
 // CHECK:STDOUT:   %IndexWith.generic: %IndexWith.type.504 = struct_value () [concrete]
 // CHECK:STDOUT:   %ElementType: type = symbolic_binding ElementType, 1 [symbolic]
@@ -294,9 +312,10 @@ fn F() { ()[()]; }
 // CHECK:STDOUT:   %IndexWith.At.type.7b0: type = fn_type @IndexWith.At, @IndexWith(%SubscriptType, %ElementType) [symbolic]
 // CHECK:STDOUT:   %IndexWith.At.62b: %IndexWith.At.type.7b0 = struct_value () [symbolic]
 // CHECK:STDOUT:   %pattern_type.946: type = pattern_type %ElementType [symbolic]
-// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 2, %Self.042 [symbolic]
-// CHECK:STDOUT:   %pattern_type.0bf: type = pattern_type %Self.binding.as_type [symbolic]
+// CHECK:STDOUT:   %Self.binding.as_type.b66: type = symbolic_binding_type Self, 2, %Self.042 [symbolic]
+// CHECK:STDOUT:   %pattern_type.0bf: type = pattern_type %Self.binding.as_type.b66 [symbolic]
 // CHECK:STDOUT:   %pattern_type.51d: type = pattern_type %SubscriptType [symbolic]
+// CHECK:STDOUT:   %empty_tuple: %empty_tuple.type = tuple_value () [concrete]
 // CHECK:STDOUT:   %IndexWith.type.5ee: type = facet_type <@IndexWith, @IndexWith(%empty_tuple.type, %empty_tuple.type)> [concrete]
 // CHECK:STDOUT:   %Self.a75: %IndexWith.type.5ee = symbolic_binding Self, 2 [symbolic]
 // CHECK:STDOUT:   %IndexWith.At.type.1a9: type = fn_type @IndexWith.At, @IndexWith(%empty_tuple.type, %empty_tuple.type) [concrete]
@@ -304,18 +323,30 @@ fn F() { ()[()]; }
 // CHECK:STDOUT:   %IndexWith.assoc_type.d10: type = assoc_entity_type @IndexWith, @IndexWith(%empty_tuple.type, %empty_tuple.type) [concrete]
 // CHECK:STDOUT:   %assoc0.78f: %IndexWith.assoc_type.d10 = assoc_entity element0, imports.%Core.import_ref.e47 [concrete]
 // CHECK:STDOUT:   %IndexWith.impl_witness: <witness> = impl_witness file.%IndexWith.impl_witness_table [concrete]
+// CHECK:STDOUT:   %pattern_type.c48: type = pattern_type %C [concrete]
 // CHECK:STDOUT:   %pattern_type.cb1: type = pattern_type %empty_tuple.type [concrete]
-// CHECK:STDOUT:   %empty_tuple.type.as.IndexWith.impl.At.type: type = fn_type @empty_tuple.type.as.IndexWith.impl.At [concrete]
-// CHECK:STDOUT:   %empty_tuple.type.as.IndexWith.impl.At: %empty_tuple.type.as.IndexWith.impl.At.type = struct_value () [concrete]
-// CHECK:STDOUT:   %IndexWith.facet: %IndexWith.type.5ee = facet_value %empty_tuple.type, (%IndexWith.impl_witness) [concrete]
+// CHECK:STDOUT:   %C.as.IndexWith.impl.At.type: type = fn_type @C.as.IndexWith.impl.At [concrete]
+// CHECK:STDOUT:   %C.as.IndexWith.impl.At: %C.as.IndexWith.impl.At.type = struct_value () [concrete]
+// CHECK:STDOUT:   %IndexWith.facet: %IndexWith.type.5ee = facet_value %C, (%IndexWith.impl_witness) [concrete]
 // CHECK:STDOUT:   %F.type: type = fn_type @F [concrete]
 // CHECK:STDOUT:   %F: %F.type = struct_value () [concrete]
+// CHECK:STDOUT:   %empty_struct: %empty_struct_type = struct_value () [concrete]
+// CHECK:STDOUT:   %C.val: %C = struct_value () [concrete]
+// CHECK:STDOUT:   %Destroy.type: type = facet_type <@Destroy> [concrete]
+// CHECK:STDOUT:   %type_where: type = facet_type <type where .Self impls <CanDestroy>> [concrete]
+// CHECK:STDOUT:   %facet_value: %type_where = facet_value %C, () [concrete]
+// CHECK:STDOUT:   %DestroyT.binding.as_type.as.Destroy.impl.Op.type.857: type = fn_type @DestroyT.binding.as_type.as.Destroy.impl.Op, @DestroyT.binding.as_type.as.Destroy.impl(%facet_value) [concrete]
+// CHECK:STDOUT:   %DestroyT.binding.as_type.as.Destroy.impl.Op.68a: %DestroyT.binding.as_type.as.Destroy.impl.Op.type.857 = struct_value () [concrete]
+// CHECK:STDOUT:   %DestroyT.binding.as_type.as.Destroy.impl.Op.specific_fn: <specific function> = specific_function %DestroyT.binding.as_type.as.Destroy.impl.Op.68a, @DestroyT.binding.as_type.as.Destroy.impl.Op(%facet_value) [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [concrete] {
 // CHECK:STDOUT:     .IndexWith = %Core.IndexWith
+// CHECK:STDOUT:     .Destroy = %Core.Destroy
+// CHECK:STDOUT:     import Core//prelude
 // CHECK:STDOUT:     import Core//core_wrong_arg_count
+// CHECK:STDOUT:     import Core//prelude/...
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Core.IndexWith: %IndexWith.type.504 = import_ref Core//core_wrong_arg_count, IndexWith, loaded [concrete = constants.%IndexWith.generic]
 // CHECK:STDOUT:   %Core.import_ref.206 = import_ref Core//core_wrong_arg_count, loc{{\d+_\d+}}, unloaded
@@ -327,26 +358,28 @@ fn F() { ()[()]; }
 // CHECK:STDOUT:   %Core.import_ref.b3bc94.2: type = import_ref Core//core_wrong_arg_count, loc{{\d+_\d+}}, loaded [symbolic = @IndexWith.%SubscriptType (constants.%SubscriptType)]
 // CHECK:STDOUT:   %Core.import_ref.8e8b42.2: type = import_ref Core//core_wrong_arg_count, loc{{\d+_\d+}}, loaded [symbolic = @IndexWith.%ElementType (constants.%ElementType)]
 // CHECK:STDOUT:   %Core.import_ref.ec5: @IndexWith.%IndexWith.type (%IndexWith.type.79c) = import_ref Core//core_wrong_arg_count, loc{{\d+_\d+}}, loaded [symbolic = @IndexWith.%Self (constants.%Self.042)]
+// CHECK:STDOUT:   %Core.Destroy: type = import_ref Core//prelude/parts/destroy, Destroy, loaded [concrete = constants.%Destroy.type]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [concrete] {
 // CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .C = %C.decl
 // CHECK:STDOUT:     .F = %F.decl
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Core.import = import Core
-// CHECK:STDOUT:   impl_decl @empty_tuple.type.as.IndexWith.impl [concrete] {} {
-// CHECK:STDOUT:     %.loc6_7.1: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple]
-// CHECK:STDOUT:     %.loc6_7.2: type = converted %.loc6_7.1, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
+// CHECK:STDOUT:   impl_decl @C.as.IndexWith.impl [concrete] {} {
+// CHECK:STDOUT:     %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C]
 // CHECK:STDOUT:     %Core.ref: <namespace> = name_ref Core, imports.%Core [concrete = imports.%Core]
 // CHECK:STDOUT:     %IndexWith.ref: %IndexWith.type.504 = name_ref IndexWith, imports.%Core.IndexWith [concrete = constants.%IndexWith.generic]
-// CHECK:STDOUT:     %.loc6_28: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple]
-// CHECK:STDOUT:     %.loc6_32: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple]
-// CHECK:STDOUT:     %.loc6_33.1: type = converted %.loc6_28, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
-// CHECK:STDOUT:     %.loc6_33.2: type = converted %.loc6_32, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
+// CHECK:STDOUT:     %.loc8_27: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple]
+// CHECK:STDOUT:     %.loc8_31: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple]
+// CHECK:STDOUT:     %.loc8_32.1: type = converted %.loc8_27, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
+// CHECK:STDOUT:     %.loc8_32.2: type = converted %.loc8_31, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
 // CHECK:STDOUT:     %IndexWith.type: type = facet_type <@IndexWith, @IndexWith(constants.%empty_tuple.type, constants.%empty_tuple.type)> [concrete = constants.%IndexWith.type.5ee]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %IndexWith.impl_witness_table = impl_witness_table (@empty_tuple.type.as.IndexWith.impl.%empty_tuple.type.as.IndexWith.impl.At.decl), @empty_tuple.type.as.IndexWith.impl [concrete]
+// CHECK:STDOUT:   %IndexWith.impl_witness_table = impl_witness_table (@C.as.IndexWith.impl.%C.as.IndexWith.impl.At.decl), @C.as.IndexWith.impl [concrete]
 // CHECK:STDOUT:   %IndexWith.impl_witness: <witness> = impl_witness %IndexWith.impl_witness_table [concrete = constants.%IndexWith.impl_witness]
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {} {}
 // CHECK:STDOUT: }
@@ -373,24 +406,24 @@ fn F() { ()[()]; }
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @empty_tuple.type.as.IndexWith.impl: %.loc6_7.2 as %IndexWith.type {
-// CHECK:STDOUT:   %empty_tuple.type.as.IndexWith.impl.At.decl: %empty_tuple.type.as.IndexWith.impl.At.type = fn_decl @empty_tuple.type.as.IndexWith.impl.At [concrete = constants.%empty_tuple.type.as.IndexWith.impl.At] {
-// CHECK:STDOUT:     %self.patt: %pattern_type.cb1 = value_binding_pattern self [concrete]
-// CHECK:STDOUT:     %self.param_patt: %pattern_type.cb1 = value_param_pattern %self.patt, call_param0 [concrete]
+// CHECK:STDOUT: impl @C.as.IndexWith.impl: %C.ref as %IndexWith.type {
+// CHECK:STDOUT:   %C.as.IndexWith.impl.At.decl: %C.as.IndexWith.impl.At.type = fn_decl @C.as.IndexWith.impl.At [concrete = constants.%C.as.IndexWith.impl.At] {
+// CHECK:STDOUT:     %self.patt: %pattern_type.c48 = value_binding_pattern self [concrete]
+// CHECK:STDOUT:     %self.param_patt: %pattern_type.c48 = value_param_pattern %self.patt, call_param0 [concrete]
 // CHECK:STDOUT:     %subscript.patt: %pattern_type.cb1 = value_binding_pattern subscript [concrete]
 // CHECK:STDOUT:     %subscript.param_patt: %pattern_type.cb1 = value_param_pattern %subscript.patt, call_param1 [concrete]
 // CHECK:STDOUT:     %return.patt: %pattern_type.cb1 = return_slot_pattern [concrete]
 // CHECK:STDOUT:     %return.param_patt: %pattern_type.cb1 = out_param_pattern %return.patt, call_param2 [concrete]
 // CHECK:STDOUT:   } {
-// CHECK:STDOUT:     %.loc7_40.1: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple]
-// CHECK:STDOUT:     %.loc7_40.2: type = converted %.loc7_40.1, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
-// CHECK:STDOUT:     %self.param: %empty_tuple.type = value_param call_param0
-// CHECK:STDOUT:     %Self.ref: type = name_ref Self, @empty_tuple.type.as.IndexWith.impl.%.loc6_7.2 [concrete = constants.%empty_tuple.type]
-// CHECK:STDOUT:     %self: %empty_tuple.type = value_binding self, %self.param
+// CHECK:STDOUT:     %.loc9_40.1: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple]
+// CHECK:STDOUT:     %.loc9_40.2: type = converted %.loc9_40.1, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
+// CHECK:STDOUT:     %self.param: %C = value_param call_param0
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, @C.as.IndexWith.impl.%C.ref [concrete = constants.%C]
+// CHECK:STDOUT:     %self: %C = value_binding self, %self.param
 // CHECK:STDOUT:     %subscript.param: %empty_tuple.type = value_param call_param1
-// CHECK:STDOUT:     %.loc7_33.1: type = splice_block %.loc7_33.3 [concrete = constants.%empty_tuple.type] {
-// CHECK:STDOUT:       %.loc7_33.2: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple]
-// CHECK:STDOUT:       %.loc7_33.3: type = converted %.loc7_33.2, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
+// CHECK:STDOUT:     %.loc9_33.1: type = splice_block %.loc9_33.3 [concrete = constants.%empty_tuple.type] {
+// CHECK:STDOUT:       %.loc9_33.2: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple]
+// CHECK:STDOUT:       %.loc9_33.3: type = converted %.loc9_33.2, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:     %subscript: %empty_tuple.type = value_binding subscript, %subscript.param
 // CHECK:STDOUT:     %return.param: ref %empty_tuple.type = out_param call_param2
@@ -398,16 +431,24 @@ fn F() { ()[()]; }
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .At = %empty_tuple.type.as.IndexWith.impl.At.decl
+// CHECK:STDOUT:   .At = %C.as.IndexWith.impl.At.decl
 // CHECK:STDOUT:   witness = file.%IndexWith.impl_witness
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness constants.%empty_struct_type [concrete = constants.%complete_type]
+// CHECK:STDOUT:   complete_type_witness = %complete_type
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: generic fn @IndexWith.At(imports.%Core.import_ref.b3bc94.2: type, imports.%Core.import_ref.8e8b42.2: type, imports.%Core.import_ref.ec5: @IndexWith.%IndexWith.type (%IndexWith.type.79c)) [from "core_wrong_arg_count.carbon"] {
 // CHECK:STDOUT:   %SubscriptType: type = symbolic_binding SubscriptType, 0 [symbolic = %SubscriptType (constants.%SubscriptType)]
 // CHECK:STDOUT:   %ElementType: type = symbolic_binding ElementType, 1 [symbolic = %ElementType (constants.%ElementType)]
 // CHECK:STDOUT:   %IndexWith.type: type = facet_type <@IndexWith, @IndexWith(%SubscriptType, %ElementType)> [symbolic = %IndexWith.type (constants.%IndexWith.type.79c)]
 // CHECK:STDOUT:   %Self: @IndexWith.At.%IndexWith.type (%IndexWith.type.79c) = symbolic_binding Self, 2 [symbolic = %Self (constants.%Self.042)]
-// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 2, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 2, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type.b66)]
 // CHECK:STDOUT:   %pattern_type.1: type = pattern_type %Self.binding.as_type [symbolic = %pattern_type.1 (constants.%pattern_type.0bf)]
 // CHECK:STDOUT:   %pattern_type.2: type = pattern_type %SubscriptType [symbolic = %pattern_type.2 (constants.%pattern_type.51d)]
 // CHECK:STDOUT:   %pattern_type.3: type = pattern_type %ElementType [symbolic = %pattern_type.3 (constants.%pattern_type.946)]
@@ -415,20 +456,33 @@ fn F() { ()[()]; }
 // CHECK:STDOUT:   fn;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: fn @empty_tuple.type.as.IndexWith.impl.At(%self.param: %empty_tuple.type, %subscript.param: %empty_tuple.type) -> %empty_tuple.type {
+// CHECK:STDOUT: fn @C.as.IndexWith.impl.At(%self.param: %C, %subscript.param: %empty_tuple.type) -> %empty_tuple.type {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %.loc8_13.1: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple]
-// CHECK:STDOUT:   %.loc8_13.2: init %empty_tuple.type = tuple_init () to %return [concrete = constants.%empty_tuple]
-// CHECK:STDOUT:   %.loc8_14: init %empty_tuple.type = converted %.loc8_13.1, %.loc8_13.2 [concrete = constants.%empty_tuple]
-// CHECK:STDOUT:   return %.loc8_14 to %return
+// CHECK:STDOUT:   %.loc10_13.1: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple]
+// CHECK:STDOUT:   %.loc10_13.2: init %empty_tuple.type = tuple_init () to %return [concrete = constants.%empty_tuple]
+// CHECK:STDOUT:   %.loc10_14: init %empty_tuple.type = converted %.loc10_13.1, %.loc10_13.2 [concrete = constants.%empty_tuple]
+// CHECK:STDOUT:   return %.loc10_14 to %return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @F() {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %.loc20_11.1: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple]
-// CHECK:STDOUT:   %.loc20_14: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple]
-// CHECK:STDOUT:   %empty_tuple: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple]
-// CHECK:STDOUT:   %.loc20_11.2: %empty_tuple.type = converted %.loc20_11.1, %empty_tuple [concrete = constants.%empty_tuple]
+// CHECK:STDOUT:   name_binding_decl {
+// CHECK:STDOUT:     %c.patt: %pattern_type.c48 = value_binding_pattern c [concrete]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.loc15_15.1: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct]
+// CHECK:STDOUT:   %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C]
+// CHECK:STDOUT:   %.loc15_15.2: ref %C = temporary_storage
+// CHECK:STDOUT:   %.loc15_15.3: init %C = class_init (), %.loc15_15.2 [concrete = constants.%C.val]
+// CHECK:STDOUT:   %.loc15_15.4: ref %C = temporary %.loc15_15.2, %.loc15_15.3
+// CHECK:STDOUT:   %.loc15_15.5: ref %C = converted %.loc15_15.1, %.loc15_15.4
+// CHECK:STDOUT:   %.loc15_15.6: %C = acquire_value %.loc15_15.5
+// CHECK:STDOUT:   %c: %C = value_binding c, %.loc15_15.6
+// CHECK:STDOUT:   %c.ref: %C = name_ref c, %c
+// CHECK:STDOUT:   %.loc23: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple]
+// CHECK:STDOUT:   %DestroyT.binding.as_type.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc15_15.4, constants.%DestroyT.binding.as_type.as.Destroy.impl.Op.68a
+// CHECK:STDOUT:   %DestroyT.binding.as_type.as.Destroy.impl.Op.specific_fn: <specific function> = specific_function constants.%DestroyT.binding.as_type.as.Destroy.impl.Op.68a, @DestroyT.binding.as_type.as.Destroy.impl.Op(constants.%facet_value) [concrete = constants.%DestroyT.binding.as_type.as.Destroy.impl.Op.specific_fn]
+// CHECK:STDOUT:   %bound_method: <bound method> = bound_method %.loc15_15.4, %DestroyT.binding.as_type.as.Destroy.impl.Op.specific_fn
+// CHECK:STDOUT:   %DestroyT.binding.as_type.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%.loc15_15.4)
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -442,7 +496,7 @@ fn F() { ()[()]; }
 // CHECK:STDOUT:   %ElementType => constants.%ElementType
 // CHECK:STDOUT:   %IndexWith.type => constants.%IndexWith.type.79c
 // CHECK:STDOUT:   %Self => constants.%Self.042
-// CHECK:STDOUT:   %Self.binding.as_type => constants.%Self.binding.as_type
+// CHECK:STDOUT:   %Self.binding.as_type => constants.%Self.binding.as_type.b66
 // CHECK:STDOUT:   %pattern_type.1 => constants.%pattern_type.0bf
 // CHECK:STDOUT:   %pattern_type.2 => constants.%pattern_type.51d
 // CHECK:STDOUT:   %pattern_type.3 => constants.%pattern_type.946
@@ -466,8 +520,8 @@ fn F() { ()[()]; }
 // CHECK:STDOUT:   %ElementType => constants.%empty_tuple.type
 // CHECK:STDOUT:   %IndexWith.type => constants.%IndexWith.type.5ee
 // CHECK:STDOUT:   %Self => constants.%IndexWith.facet
-// CHECK:STDOUT:   %Self.binding.as_type => constants.%empty_tuple.type
-// CHECK:STDOUT:   %pattern_type.1 => constants.%pattern_type.cb1
+// CHECK:STDOUT:   %Self.binding.as_type => constants.%C
+// CHECK:STDOUT:   %pattern_type.1 => constants.%pattern_type.c48
 // CHECK:STDOUT:   %pattern_type.2 => constants.%pattern_type.cb1
 // CHECK:STDOUT:   %pattern_type.3 => constants.%pattern_type.cb1
 // CHECK:STDOUT: }

+ 106 - 142
toolchain/check/testdata/operators/overloaded/index_with_prelude.carbon

@@ -34,14 +34,18 @@ let x: ElementType = c[s];
 
 library "[[@TEST_NAME]]";
 
-impl (i32, i32) as Core.IndexWith(Core.IntLiteral()) where .ElementType = i32 {
-  fn At[self: Self](subscript: Core.IntLiteral()) -> i32 {
+class C {
+  adapt ();
+}
+
+impl (C, C) as Core.IndexWith(Core.IntLiteral()) where .ElementType = C {
+  fn At[self: Self](subscript: Core.IntLiteral()) -> C {
     return self.0;
   }
 }
 
-let s: (i32, i32) = (1, 5);
-let e: i32 = s[0];
+let s: (C, C) = (() as C, () as C);
+let e: C = s[0];
 
 // --- fail_invalid_subscript_type.carbon
 
@@ -267,15 +271,13 @@ let x: i32 = c[0];
 // CHECK:STDOUT: --- overloaded_builtin.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
-// CHECK:STDOUT:   %int_32: Core.IntLiteral = int_value 32 [concrete]
-// CHECK:STDOUT:   %Int.type: type = generic_class_type @Int [concrete]
-// CHECK:STDOUT:   %Int.generic: %Int.type = struct_value () [concrete]
-// CHECK:STDOUT:   %N: Core.IntLiteral = symbolic_binding N, 0 [symbolic]
-// CHECK:STDOUT:   %pattern_type.dc0: type = pattern_type Core.IntLiteral [concrete]
-// CHECK:STDOUT:   %i32: type = class_type @Int, @Int(%int_32) [concrete]
+// CHECK:STDOUT:   %C: type = class_type @C [concrete]
+// CHECK:STDOUT:   %empty_tuple.type: type = tuple_type () [concrete]
+// CHECK:STDOUT:   %empty_tuple.af4: %empty_tuple.type = tuple_value () [concrete]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %empty_tuple.type [concrete]
 // CHECK:STDOUT:   %tuple.type.24b: type = tuple_type (type, type) [concrete]
-// CHECK:STDOUT:   %tuple.95a: %tuple.type.24b = tuple_value (%i32, %i32) [concrete]
-// CHECK:STDOUT:   %tuple.type.d07: type = tuple_type (%i32, %i32) [concrete]
+// CHECK:STDOUT:   %tuple.0d6: %tuple.type.24b = tuple_value (%C, %C) [concrete]
+// CHECK:STDOUT:   %tuple.type.56b: type = tuple_type (%C, %C) [concrete]
 // CHECK:STDOUT:   %IndexWith.type.504: type = generic_interface_type @IndexWith [concrete]
 // CHECK:STDOUT:   %IndexWith.generic: %IndexWith.type.504 = struct_value () [concrete]
 // CHECK:STDOUT:   %SubscriptType: type = symbolic_binding SubscriptType, 0 [symbolic]
@@ -291,210 +293,172 @@ let x: i32 = c[0];
 // CHECK:STDOUT:   %.Self.binding.as_type: type = symbolic_binding_type .Self, %.Self [symbolic_self]
 // CHECK:STDOUT:   %IndexWith.lookup_impl_witness.e03: <witness> = lookup_impl_witness %.Self, @IndexWith, @IndexWith(Core.IntLiteral) [symbolic_self]
 // CHECK:STDOUT:   %impl.elem0.f03: type = impl_witness_access %IndexWith.lookup_impl_witness.e03, element0 [symbolic_self]
-// CHECK:STDOUT:   %IndexWith_where.type: type = facet_type <@IndexWith, @IndexWith(Core.IntLiteral) where %impl.elem0.f03 = %i32> [concrete]
+// CHECK:STDOUT:   %IndexWith_where.type: type = facet_type <@IndexWith, @IndexWith(Core.IntLiteral) where %impl.elem0.f03 = %C> [concrete]
 // CHECK:STDOUT:   %IndexWith.impl_witness: <witness> = impl_witness file.%IndexWith.impl_witness_table [concrete]
-// CHECK:STDOUT:   %pattern_type.511: type = pattern_type %tuple.type.d07 [concrete]
-// CHECK:STDOUT:   %pattern_type.7ce: type = pattern_type %i32 [concrete]
+// CHECK:STDOUT:   %pattern_type.99e: type = pattern_type %tuple.type.56b [concrete]
+// CHECK:STDOUT:   %pattern_type.dc0: type = pattern_type Core.IntLiteral [concrete]
+// CHECK:STDOUT:   %pattern_type.c48: type = pattern_type %C [concrete]
 // CHECK:STDOUT:   %tuple.type.as.IndexWith.impl.At.type: type = fn_type @tuple.type.as.IndexWith.impl.At [concrete]
 // CHECK:STDOUT:   %tuple.type.as.IndexWith.impl.At: %tuple.type.as.IndexWith.impl.At.type = struct_value () [concrete]
-// CHECK:STDOUT:   %IndexWith.facet: %IndexWith.type.8ab = facet_value %tuple.type.d07, (%IndexWith.impl_witness) [concrete]
+// CHECK:STDOUT:   %IndexWith.facet: %IndexWith.type.8ab = facet_value %tuple.type.56b, (%IndexWith.impl_witness) [concrete]
 // CHECK:STDOUT:   %int_0: Core.IntLiteral = int_value 0 [concrete]
-// CHECK:STDOUT:   %Copy.type: type = facet_type <@Copy> [concrete]
-// CHECK:STDOUT:   %Copy.Op.type: type = fn_type @Copy.Op [concrete]
-// CHECK:STDOUT:   %Int.as.Copy.impl.Op.type.413: type = fn_type @Int.as.Copy.impl.Op, @Int.as.Copy.impl(%N) [symbolic]
-// CHECK:STDOUT:   %Int.as.Copy.impl.Op.2d6: %Int.as.Copy.impl.Op.type.413 = struct_value () [symbolic]
-// CHECK:STDOUT:   %Copy.impl_witness.09c: <witness> = impl_witness imports.%Copy.impl_witness_table.e1c, @Int.as.Copy.impl(%int_32) [concrete]
-// CHECK:STDOUT:   %Int.as.Copy.impl.Op.type.60b: type = fn_type @Int.as.Copy.impl.Op, @Int.as.Copy.impl(%int_32) [concrete]
-// CHECK:STDOUT:   %Int.as.Copy.impl.Op.c85: %Int.as.Copy.impl.Op.type.60b = struct_value () [concrete]
-// CHECK:STDOUT:   %Copy.facet: %Copy.type = facet_value %i32, (%Copy.impl_witness.09c) [concrete]
-// CHECK:STDOUT:   %.fe5: type = fn_type_with_self_type %Copy.Op.type, %Copy.facet [concrete]
-// CHECK:STDOUT:   %Int.as.Copy.impl.Op.specific_fn: <specific function> = specific_function %Int.as.Copy.impl.Op.c85, @Int.as.Copy.impl.Op(%int_32) [concrete]
-// CHECK:STDOUT:   %int_1.5b8: Core.IntLiteral = int_value 1 [concrete]
-// CHECK:STDOUT:   %int_5.64b: Core.IntLiteral = int_value 5 [concrete]
-// CHECK:STDOUT:   %tuple.type.f94: type = tuple_type (Core.IntLiteral, Core.IntLiteral) [concrete]
-// CHECK:STDOUT:   %tuple.f6b: %tuple.type.f94 = tuple_value (%int_1.5b8, %int_5.64b) [concrete]
-// CHECK:STDOUT:   %ImplicitAs.type.cc7: type = generic_interface_type @ImplicitAs [concrete]
-// CHECK:STDOUT:   %ImplicitAs.generic: %ImplicitAs.type.cc7 = struct_value () [concrete]
-// CHECK:STDOUT:   %ImplicitAs.type.d14: type = facet_type <@ImplicitAs, @ImplicitAs(%i32)> [concrete]
-// CHECK:STDOUT:   %ImplicitAs.Convert.type.1b6: type = fn_type @ImplicitAs.Convert, @ImplicitAs(%i32) [concrete]
-// CHECK:STDOUT:   %To: Core.IntLiteral = symbolic_binding To, 0 [symbolic]
-// CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.412: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%To) [symbolic]
-// CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert.740: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.412 = struct_value () [symbolic]
-// CHECK:STDOUT:   %ImplicitAs.impl_witness.ec0: <witness> = impl_witness imports.%ImplicitAs.impl_witness_table.99e, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete]
-// CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.84b: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete]
-// CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert.6f0: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.84b = struct_value () [concrete]
-// CHECK:STDOUT:   %ImplicitAs.facet: %ImplicitAs.type.d14 = facet_value Core.IntLiteral, (%ImplicitAs.impl_witness.ec0) [concrete]
-// CHECK:STDOUT:   %.d28: type = fn_type_with_self_type %ImplicitAs.Convert.type.1b6, %ImplicitAs.facet [concrete]
-// CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.3d4: <bound method> = bound_method %int_1.5b8, %Core.IntLiteral.as.ImplicitAs.impl.Convert.6f0 [concrete]
-// CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn: <specific function> = specific_function %Core.IntLiteral.as.ImplicitAs.impl.Convert.6f0, @Core.IntLiteral.as.ImplicitAs.impl.Convert(%int_32) [concrete]
-// CHECK:STDOUT:   %bound_method.d3a: <bound method> = bound_method %int_1.5b8, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete]
-// CHECK:STDOUT:   %int_1.5d2: %i32 = int_value 1 [concrete]
-// CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.b1d: <bound method> = bound_method %int_5.64b, %Core.IntLiteral.as.ImplicitAs.impl.Convert.6f0 [concrete]
-// CHECK:STDOUT:   %bound_method.06d: <bound method> = bound_method %int_5.64b, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete]
-// CHECK:STDOUT:   %int_5.0f6: %i32 = int_value 5 [concrete]
-// CHECK:STDOUT:   %tuple.bc2: %tuple.type.d07 = tuple_value (%int_1.5d2, %int_5.0f6) [concrete]
-// CHECK:STDOUT:   %.a89: type = fn_type_with_self_type %IndexWith.At.type.1ab, %IndexWith.facet [concrete]
+// CHECK:STDOUT:   %empty_tuple.a69: %C = tuple_value () [concrete]
+// CHECK:STDOUT:   %tuple.8e9: %tuple.type.56b = tuple_value (%empty_tuple.a69, %empty_tuple.a69) [concrete]
+// CHECK:STDOUT:   %.7d9: type = fn_type_with_self_type %IndexWith.At.type.1ab, %IndexWith.facet [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [concrete] {
-// CHECK:STDOUT:     .Int = %Core.Int
 // CHECK:STDOUT:     .IndexWith = %Core.IndexWith
 // CHECK:STDOUT:     .IntLiteral = %Core.IntLiteral
-// CHECK:STDOUT:     .Copy = %Core.Copy
-// CHECK:STDOUT:     .ImplicitAs = %Core.ImplicitAs
 // CHECK:STDOUT:     import Core//prelude
 // CHECK:STDOUT:     import Core//prelude/...
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Core.Int: %Int.type = import_ref Core//prelude/types/int, Int, loaded [concrete = constants.%Int.generic]
 // CHECK:STDOUT:   %Core.IndexWith: %IndexWith.type.504 = import_ref Core//prelude/operators/index, IndexWith, loaded [concrete = constants.%IndexWith.generic]
 // CHECK:STDOUT:   %Core.import_ref.1f3: @IndexWith.%IndexWith.assoc_type (%IndexWith.assoc_type.a96) = import_ref Core//prelude/operators/index, loc{{\d+_\d+}}, loaded [symbolic = @IndexWith.%assoc0 (constants.%assoc0.fe9)]
 // CHECK:STDOUT:   %Core.import_ref.156: type = import_ref Core//prelude/operators/index, loc{{\d+_\d+}}, loaded [concrete = %ElementType]
 // CHECK:STDOUT:   %Core.IntLiteral: %IntLiteral.type = import_ref Core//prelude/types/int_literal, IntLiteral, loaded [concrete = constants.%IntLiteral]
 // CHECK:STDOUT:   %Core.import_ref.6c8 = import_ref Core//prelude/operators/index, loc{{\d+_\d+}}, unloaded
 // CHECK:STDOUT:   %ElementType: type = assoc_const_decl @ElementType [concrete] {}
-// CHECK:STDOUT:   %Core.Copy: type = import_ref Core//prelude/copy, Copy, loaded [concrete = constants.%Copy.type]
-// CHECK:STDOUT:   %Core.import_ref.edf: @Int.as.Copy.impl.%Int.as.Copy.impl.Op.type (%Int.as.Copy.impl.Op.type.413) = import_ref Core//prelude/types/int, loc{{\d+_\d+}}, loaded [symbolic = @Int.as.Copy.impl.%Int.as.Copy.impl.Op (constants.%Int.as.Copy.impl.Op.2d6)]
-// CHECK:STDOUT:   %Copy.impl_witness_table.e1c = impl_witness_table (%Core.import_ref.edf), @Int.as.Copy.impl [concrete]
-// CHECK:STDOUT:   %Core.ImplicitAs: %ImplicitAs.type.cc7 = import_ref Core//prelude/operators/as, ImplicitAs, loaded [concrete = constants.%ImplicitAs.generic]
-// CHECK:STDOUT:   %Core.import_ref.3e1: @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert.type (%Core.IntLiteral.as.ImplicitAs.impl.Convert.type.412) = import_ref Core//prelude/types/int, loc{{\d+_\d+}}, loaded [symbolic = @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert (constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.740)]
-// CHECK:STDOUT:   %ImplicitAs.impl_witness_table.99e = impl_witness_table (%Core.import_ref.3e1), @Core.IntLiteral.as.ImplicitAs.impl [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [concrete] {
 // CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .C = %C.decl
 // CHECK:STDOUT:     .s = %s
 // CHECK:STDOUT:     .e = %e
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
 // CHECK:STDOUT:   impl_decl @tuple.type.as.IndexWith.impl [concrete] {} {
-// CHECK:STDOUT:     %int_32.loc4_7: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
-// CHECK:STDOUT:     %i32.loc4_7: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
-// CHECK:STDOUT:     %int_32.loc4_12: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
-// CHECK:STDOUT:     %i32.loc4_12: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
-// CHECK:STDOUT:     %.loc4_15.1: %tuple.type.24b = tuple_literal (%i32.loc4_7, %i32.loc4_12) [concrete = constants.%tuple.95a]
-// CHECK:STDOUT:     %.loc4_15.2: type = converted %.loc4_15.1, constants.%tuple.type.d07 [concrete = constants.%tuple.type.d07]
-// CHECK:STDOUT:     %Core.ref.loc4_20: <namespace> = name_ref Core, imports.%Core [concrete = imports.%Core]
+// CHECK:STDOUT:     %C.ref.loc8_7: type = name_ref C, file.%C.decl [concrete = constants.%C]
+// CHECK:STDOUT:     %C.ref.loc8_10: type = name_ref C, file.%C.decl [concrete = constants.%C]
+// CHECK:STDOUT:     %.loc8_11.1: %tuple.type.24b = tuple_literal (%C.ref.loc8_7, %C.ref.loc8_10) [concrete = constants.%tuple.0d6]
+// CHECK:STDOUT:     %.loc8_11.2: type = converted %.loc8_11.1, constants.%tuple.type.56b [concrete = constants.%tuple.type.56b]
+// CHECK:STDOUT:     %Core.ref.loc8_16: <namespace> = name_ref Core, imports.%Core [concrete = imports.%Core]
 // CHECK:STDOUT:     %IndexWith.ref: %IndexWith.type.504 = name_ref IndexWith, imports.%Core.IndexWith [concrete = constants.%IndexWith.generic]
-// CHECK:STDOUT:     %Core.ref.loc4_35: <namespace> = name_ref Core, imports.%Core [concrete = imports.%Core]
+// CHECK:STDOUT:     %Core.ref.loc8_31: <namespace> = name_ref Core, imports.%Core [concrete = imports.%Core]
 // CHECK:STDOUT:     %IntLiteral.ref: %IntLiteral.type = name_ref IntLiteral, imports.%Core.IntLiteral [concrete = constants.%IntLiteral]
 // CHECK:STDOUT:     %IntLiteral.call: init type = call %IntLiteral.ref() [concrete = Core.IntLiteral]
-// CHECK:STDOUT:     %.loc4_52.1: type = value_of_initializer %IntLiteral.call [concrete = Core.IntLiteral]
-// CHECK:STDOUT:     %.loc4_52.2: type = converted %IntLiteral.call, %.loc4_52.1 [concrete = Core.IntLiteral]
+// CHECK:STDOUT:     %.loc8_48.1: type = value_of_initializer %IntLiteral.call [concrete = Core.IntLiteral]
+// CHECK:STDOUT:     %.loc8_48.2: type = converted %IntLiteral.call, %.loc8_48.1 [concrete = Core.IntLiteral]
 // CHECK:STDOUT:     %IndexWith.type: type = facet_type <@IndexWith, @IndexWith(Core.IntLiteral)> [concrete = constants.%IndexWith.type.8ab]
 // CHECK:STDOUT:     %.Self: %IndexWith.type.8ab = symbolic_binding .Self [symbolic_self = constants.%.Self]
 // CHECK:STDOUT:     %.Self.ref: %IndexWith.type.8ab = name_ref .Self, %.Self [symbolic_self = constants.%.Self]
-// CHECK:STDOUT:     %.loc4_60.1: %IndexWith.assoc_type.972 = specific_constant imports.%Core.import_ref.1f3, @IndexWith(Core.IntLiteral) [concrete = constants.%assoc0.b5d]
-// CHECK:STDOUT:     %ElementType.ref: %IndexWith.assoc_type.972 = name_ref ElementType, %.loc4_60.1 [concrete = constants.%assoc0.b5d]
+// CHECK:STDOUT:     %.loc8_56.1: %IndexWith.assoc_type.972 = specific_constant imports.%Core.import_ref.1f3, @IndexWith(Core.IntLiteral) [concrete = constants.%assoc0.b5d]
+// CHECK:STDOUT:     %ElementType.ref: %IndexWith.assoc_type.972 = name_ref ElementType, %.loc8_56.1 [concrete = constants.%assoc0.b5d]
 // CHECK:STDOUT:     %.Self.as_type: type = facet_access_type %.Self.ref [symbolic_self = constants.%.Self.binding.as_type]
-// CHECK:STDOUT:     %.loc4_60.2: type = converted %.Self.ref, %.Self.as_type [symbolic_self = constants.%.Self.binding.as_type]
+// CHECK:STDOUT:     %.loc8_56.2: type = converted %.Self.ref, %.Self.as_type [symbolic_self = constants.%.Self.binding.as_type]
 // CHECK:STDOUT:     %impl.elem0: type = impl_witness_access constants.%IndexWith.lookup_impl_witness.e03, element0 [symbolic_self = constants.%impl.elem0.f03]
-// CHECK:STDOUT:     %int_32.loc4_75: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
-// CHECK:STDOUT:     %i32.loc4_75: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
-// CHECK:STDOUT:     %.loc4_54: type = where_expr %.Self [concrete = constants.%IndexWith_where.type] {
+// CHECK:STDOUT:     %C.ref.loc8_71: type = name_ref C, file.%C.decl [concrete = constants.%C]
+// CHECK:STDOUT:     %.loc8_50: type = where_expr %.Self [concrete = constants.%IndexWith_where.type] {
 // CHECK:STDOUT:       requirement_base_facet_type constants.%IndexWith.type.8ab
-// CHECK:STDOUT:       requirement_rewrite %impl.elem0, %i32.loc4_75
+// CHECK:STDOUT:       requirement_rewrite %impl.elem0, %C.ref.loc8_71
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %IndexWith.impl_witness_table = impl_witness_table (%impl_witness_assoc_constant, @tuple.type.as.IndexWith.impl.%tuple.type.as.IndexWith.impl.At.decl), @tuple.type.as.IndexWith.impl [concrete]
 // CHECK:STDOUT:   %IndexWith.impl_witness: <witness> = impl_witness %IndexWith.impl_witness_table [concrete = constants.%IndexWith.impl_witness]
-// CHECK:STDOUT:   %impl_witness_assoc_constant: type = impl_witness_assoc_constant constants.%i32 [concrete = constants.%i32]
+// CHECK:STDOUT:   %impl_witness_assoc_constant: type = impl_witness_assoc_constant constants.%C [concrete = constants.%C]
 // CHECK:STDOUT:   name_binding_decl {
-// CHECK:STDOUT:     %s.patt: %pattern_type.511 = value_binding_pattern s [concrete]
+// CHECK:STDOUT:     %s.patt: %pattern_type.99e = value_binding_pattern s [concrete]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc10_17.1: type = splice_block %.loc10_17.3 [concrete = constants.%tuple.type.d07] {
-// CHECK:STDOUT:     %int_32.loc10_9: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
-// CHECK:STDOUT:     %i32.loc10_9: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
-// CHECK:STDOUT:     %int_32.loc10_14: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
-// CHECK:STDOUT:     %i32.loc10_14: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
-// CHECK:STDOUT:     %.loc10_17.2: %tuple.type.24b = tuple_literal (%i32.loc10_9, %i32.loc10_14) [concrete = constants.%tuple.95a]
-// CHECK:STDOUT:     %.loc10_17.3: type = converted %.loc10_17.2, constants.%tuple.type.d07 [concrete = constants.%tuple.type.d07]
+// CHECK:STDOUT:   %.loc14_13.1: type = splice_block %.loc14_13.3 [concrete = constants.%tuple.type.56b] {
+// CHECK:STDOUT:     %C.ref.loc14_9: type = name_ref C, %C.decl [concrete = constants.%C]
+// CHECK:STDOUT:     %C.ref.loc14_12: type = name_ref C, %C.decl [concrete = constants.%C]
+// CHECK:STDOUT:     %.loc14_13.2: %tuple.type.24b = tuple_literal (%C.ref.loc14_9, %C.ref.loc14_12) [concrete = constants.%tuple.0d6]
+// CHECK:STDOUT:     %.loc14_13.3: type = converted %.loc14_13.2, constants.%tuple.type.56b [concrete = constants.%tuple.type.56b]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %impl.elem0.loc10_26.1: %.d28 = impl_witness_access constants.%ImplicitAs.impl_witness.ec0, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.6f0]
-// CHECK:STDOUT:   %bound_method.loc10_26.1: <bound method> = bound_method @__global_init.%int_1, %impl.elem0.loc10_26.1 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.3d4]
-// CHECK:STDOUT:   %specific_fn.loc10_26.1: <specific function> = specific_function %impl.elem0.loc10_26.1, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn]
-// CHECK:STDOUT:   %bound_method.loc10_26.2: <bound method> = bound_method @__global_init.%int_1, %specific_fn.loc10_26.1 [concrete = constants.%bound_method.d3a]
-// CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc10_26.1: init %i32 = call %bound_method.loc10_26.2(@__global_init.%int_1) [concrete = constants.%int_1.5d2]
-// CHECK:STDOUT:   %.loc10_26.1: %i32 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc10_26.1 [concrete = constants.%int_1.5d2]
-// CHECK:STDOUT:   %.loc10_26.2: %i32 = converted @__global_init.%int_1, %.loc10_26.1 [concrete = constants.%int_1.5d2]
-// CHECK:STDOUT:   %impl.elem0.loc10_26.2: %.d28 = impl_witness_access constants.%ImplicitAs.impl_witness.ec0, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.6f0]
-// CHECK:STDOUT:   %bound_method.loc10_26.3: <bound method> = bound_method @__global_init.%int_5, %impl.elem0.loc10_26.2 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.b1d]
-// CHECK:STDOUT:   %specific_fn.loc10_26.2: <specific function> = specific_function %impl.elem0.loc10_26.2, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn]
-// CHECK:STDOUT:   %bound_method.loc10_26.4: <bound method> = bound_method @__global_init.%int_5, %specific_fn.loc10_26.2 [concrete = constants.%bound_method.06d]
-// CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc10_26.2: init %i32 = call %bound_method.loc10_26.4(@__global_init.%int_5) [concrete = constants.%int_5.0f6]
-// CHECK:STDOUT:   %.loc10_26.3: %i32 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc10_26.2 [concrete = constants.%int_5.0f6]
-// CHECK:STDOUT:   %.loc10_26.4: %i32 = converted @__global_init.%int_5, %.loc10_26.3 [concrete = constants.%int_5.0f6]
-// CHECK:STDOUT:   %tuple: %tuple.type.d07 = tuple_value (%.loc10_26.2, %.loc10_26.4) [concrete = constants.%tuple.bc2]
-// CHECK:STDOUT:   %.loc10_26.5: %tuple.type.d07 = converted @__global_init.%.loc10, %tuple [concrete = constants.%tuple.bc2]
-// CHECK:STDOUT:   %s: %tuple.type.d07 = value_binding s, %.loc10_26.5
+// CHECK:STDOUT:   %tuple.loc14: %tuple.type.56b = tuple_value (@__global_init.%.loc14_21.2, @__global_init.%.loc14_30.2) [concrete = constants.%tuple.8e9]
+// CHECK:STDOUT:   %.loc14_34: %tuple.type.56b = converted @__global_init.%.loc14_34, %tuple.loc14 [concrete = constants.%tuple.8e9]
+// CHECK:STDOUT:   %s: %tuple.type.56b = value_binding s, %.loc14_34
 // CHECK:STDOUT:   name_binding_decl {
-// CHECK:STDOUT:     %e.patt: %pattern_type.7ce = value_binding_pattern e [concrete]
+// CHECK:STDOUT:     %e.patt: %pattern_type.c48 = value_binding_pattern e [concrete]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc11_8: type = splice_block %i32.loc11 [concrete = constants.%i32] {
-// CHECK:STDOUT:     %int_32.loc11: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
-// CHECK:STDOUT:     %i32.loc11: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
-// CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc11_17.1: %i32 = value_of_initializer @__global_init.%tuple.type.as.IndexWith.impl.At.call
-// CHECK:STDOUT:   %.loc11_17.2: %i32 = converted @__global_init.%tuple.type.as.IndexWith.impl.At.call, %.loc11_17.1
-// CHECK:STDOUT:   %e: %i32 = value_binding e, %.loc11_17.2
+// CHECK:STDOUT:   %C.ref.loc15: type = name_ref C, %C.decl [concrete = constants.%C]
+// CHECK:STDOUT:   %.loc15_15.1: init %empty_tuple.type = as_compatible @__global_init.%tuple.type.as.IndexWith.impl.At.call
+// CHECK:STDOUT:   %.loc15_15.2: ref %empty_tuple.type = temporary_storage
+// CHECK:STDOUT:   %.loc15_15.3: ref %empty_tuple.type = temporary %.loc15_15.2, %.loc15_15.1
+// CHECK:STDOUT:   %tuple.loc15: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple.af4]
+// CHECK:STDOUT:   %.loc15_15.4: %C = as_compatible %tuple.loc15 [concrete = constants.%empty_tuple.a69]
+// CHECK:STDOUT:   %.loc15_15.5: %C = converted @__global_init.%tuple.type.as.IndexWith.impl.At.call, %.loc15_15.4 [concrete = constants.%empty_tuple.a69]
+// CHECK:STDOUT:   %e: %C = value_binding e, %.loc15_15.5
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @tuple.type.as.IndexWith.impl: %.loc4_15.2 as %.loc4_54 {
+// CHECK:STDOUT: impl @tuple.type.as.IndexWith.impl: %.loc8_11.2 as %.loc8_50 {
 // CHECK:STDOUT:   %tuple.type.as.IndexWith.impl.At.decl: %tuple.type.as.IndexWith.impl.At.type = fn_decl @tuple.type.as.IndexWith.impl.At [concrete = constants.%tuple.type.as.IndexWith.impl.At] {
-// CHECK:STDOUT:     %self.patt: %pattern_type.511 = value_binding_pattern self [concrete]
-// CHECK:STDOUT:     %self.param_patt: %pattern_type.511 = value_param_pattern %self.patt, call_param0 [concrete]
+// CHECK:STDOUT:     %self.patt: %pattern_type.99e = value_binding_pattern self [concrete]
+// CHECK:STDOUT:     %self.param_patt: %pattern_type.99e = value_param_pattern %self.patt, call_param0 [concrete]
 // CHECK:STDOUT:     %subscript.patt: %pattern_type.dc0 = value_binding_pattern subscript [concrete]
 // CHECK:STDOUT:     %subscript.param_patt: %pattern_type.dc0 = value_param_pattern %subscript.patt, call_param1 [concrete]
-// CHECK:STDOUT:     %return.patt: %pattern_type.7ce = return_slot_pattern [concrete]
-// CHECK:STDOUT:     %return.param_patt: %pattern_type.7ce = out_param_pattern %return.patt, call_param2 [concrete]
+// CHECK:STDOUT:     %return.patt: %pattern_type.c48 = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: %pattern_type.c48 = out_param_pattern %return.patt, call_param2 [concrete]
 // CHECK:STDOUT:   } {
-// CHECK:STDOUT:     %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
-// CHECK:STDOUT:     %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
-// CHECK:STDOUT:     %self.param: %tuple.type.d07 = value_param call_param0
-// CHECK:STDOUT:     %Self.ref: type = name_ref Self, @tuple.type.as.IndexWith.impl.%.loc4_15.2 [concrete = constants.%tuple.type.d07]
-// CHECK:STDOUT:     %self: %tuple.type.d07 = value_binding self, %self.param
+// CHECK:STDOUT:     %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C]
+// CHECK:STDOUT:     %self.param: %tuple.type.56b = value_param call_param0
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, @tuple.type.as.IndexWith.impl.%.loc8_11.2 [concrete = constants.%tuple.type.56b]
+// CHECK:STDOUT:     %self: %tuple.type.56b = value_binding self, %self.param
 // CHECK:STDOUT:     %subscript.param: Core.IntLiteral = value_param call_param1
-// CHECK:STDOUT:     %.loc5_48.1: type = splice_block %.loc5_48.3 [concrete = Core.IntLiteral] {
+// CHECK:STDOUT:     %.loc9_48.1: type = splice_block %.loc9_48.3 [concrete = Core.IntLiteral] {
 // CHECK:STDOUT:       %Core.ref: <namespace> = name_ref Core, imports.%Core [concrete = imports.%Core]
 // CHECK:STDOUT:       %IntLiteral.ref: %IntLiteral.type = name_ref IntLiteral, imports.%Core.IntLiteral [concrete = constants.%IntLiteral]
 // CHECK:STDOUT:       %IntLiteral.call: init type = call %IntLiteral.ref() [concrete = Core.IntLiteral]
-// CHECK:STDOUT:       %.loc5_48.2: type = value_of_initializer %IntLiteral.call [concrete = Core.IntLiteral]
-// CHECK:STDOUT:       %.loc5_48.3: type = converted %IntLiteral.call, %.loc5_48.2 [concrete = Core.IntLiteral]
+// CHECK:STDOUT:       %.loc9_48.2: type = value_of_initializer %IntLiteral.call [concrete = Core.IntLiteral]
+// CHECK:STDOUT:       %.loc9_48.3: type = converted %IntLiteral.call, %.loc9_48.2 [concrete = Core.IntLiteral]
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:     %subscript: Core.IntLiteral = value_binding subscript, %subscript.param
-// CHECK:STDOUT:     %return.param: ref %i32 = out_param call_param2
-// CHECK:STDOUT:     %return: ref %i32 = return_slot %return.param
+// CHECK:STDOUT:     %return.param: ref %C = out_param call_param2
+// CHECK:STDOUT:     %return: ref %C = return_slot %return.param
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .C = <poisoned>
 // CHECK:STDOUT:   .At = %tuple.type.as.IndexWith.impl.At.decl
 // CHECK:STDOUT:   witness = file.%IndexWith.impl_witness
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: fn @tuple.type.as.IndexWith.impl.At(%self.param: %tuple.type.d07, %subscript.param: Core.IntLiteral) -> %i32 {
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT:   %.loc5_10: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple.af4]
+// CHECK:STDOUT:   %.loc5_11: type = converted %.loc5_10, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
+// CHECK:STDOUT:   adapt_decl %.loc5_11 [concrete]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness constants.%empty_tuple.type [concrete = constants.%complete_type]
+// CHECK:STDOUT:   complete_type_witness = %complete_type
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @tuple.type.as.IndexWith.impl.At(%self.param: %tuple.type.56b, %subscript.param: Core.IntLiteral) -> %C {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %self.ref: %tuple.type.d07 = name_ref self, %self
+// CHECK:STDOUT:   %self.ref: %tuple.type.56b = name_ref self, %self
 // CHECK:STDOUT:   %int_0: Core.IntLiteral = int_value 0 [concrete = constants.%int_0]
-// CHECK:STDOUT:   %tuple.elem0: %i32 = tuple_access %self.ref, element0
-// CHECK:STDOUT:   %impl.elem0: %.fe5 = impl_witness_access constants.%Copy.impl_witness.09c, element0 [concrete = constants.%Int.as.Copy.impl.Op.c85]
-// CHECK:STDOUT:   %bound_method.loc6_16.1: <bound method> = bound_method %tuple.elem0, %impl.elem0
-// CHECK:STDOUT:   %specific_fn: <specific function> = specific_function %impl.elem0, @Int.as.Copy.impl.Op(constants.%int_32) [concrete = constants.%Int.as.Copy.impl.Op.specific_fn]
-// CHECK:STDOUT:   %bound_method.loc6_16.2: <bound method> = bound_method %tuple.elem0, %specific_fn
-// CHECK:STDOUT:   %Int.as.Copy.impl.Op.call: init %i32 = call %bound_method.loc6_16.2(%tuple.elem0)
-// CHECK:STDOUT:   return %Int.as.Copy.impl.Op.call to %return
+// CHECK:STDOUT:   %tuple.elem0: %C = tuple_access %self.ref, element0
+// CHECK:STDOUT:   %.loc10_18.1: %empty_tuple.type = as_compatible %tuple.elem0
+// CHECK:STDOUT:   %.loc10_18.2: ref %empty_tuple.type = as_compatible %return
+// CHECK:STDOUT:   %.loc10_18.3: init %empty_tuple.type = tuple_init () to %.loc10_18.2 [concrete = constants.%empty_tuple.af4]
+// CHECK:STDOUT:   %.loc10_18.4: init %C = as_compatible %.loc10_18.3 [concrete = constants.%empty_tuple.a69]
+// CHECK:STDOUT:   %.loc10_18.5: init %C = converted %tuple.elem0, %.loc10_18.4 [concrete = constants.%empty_tuple.a69]
+// CHECK:STDOUT:   return %.loc10_18.5 to %return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1.5b8]
-// CHECK:STDOUT:   %int_5: Core.IntLiteral = int_value 5 [concrete = constants.%int_5.64b]
-// CHECK:STDOUT:   %.loc10: %tuple.type.f94 = tuple_literal (%int_1, %int_5) [concrete = constants.%tuple.f6b]
-// CHECK:STDOUT:   %s.ref: %tuple.type.d07 = name_ref s, file.%s
+// CHECK:STDOUT:   %.loc14_19: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple.af4]
+// CHECK:STDOUT:   %C.ref.loc14_24: type = name_ref C, file.%C.decl [concrete = constants.%C]
+// CHECK:STDOUT:   %empty_tuple.loc14_19: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple.af4]
+// CHECK:STDOUT:   %.loc14_21.1: %C = as_compatible %empty_tuple.loc14_19 [concrete = constants.%empty_tuple.a69]
+// CHECK:STDOUT:   %.loc14_21.2: %C = converted %.loc14_19, %.loc14_21.1 [concrete = constants.%empty_tuple.a69]
+// CHECK:STDOUT:   %.loc14_28: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple.af4]
+// CHECK:STDOUT:   %C.ref.loc14_33: type = name_ref C, file.%C.decl [concrete = constants.%C]
+// CHECK:STDOUT:   %empty_tuple.loc14_28: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple.af4]
+// CHECK:STDOUT:   %.loc14_30.1: %C = as_compatible %empty_tuple.loc14_28 [concrete = constants.%empty_tuple.a69]
+// CHECK:STDOUT:   %.loc14_30.2: %C = converted %.loc14_28, %.loc14_30.1 [concrete = constants.%empty_tuple.a69]
+// CHECK:STDOUT:   %.loc14_34: %tuple.type.56b = tuple_literal (%.loc14_21.2, %.loc14_30.2) [concrete = constants.%tuple.8e9]
+// CHECK:STDOUT:   %s.ref: %tuple.type.56b = name_ref s, file.%s
 // CHECK:STDOUT:   %int_0: Core.IntLiteral = int_value 0 [concrete = constants.%int_0]
-// CHECK:STDOUT:   %impl.elem1: %.a89 = impl_witness_access constants.%IndexWith.impl_witness, element1 [concrete = constants.%tuple.type.as.IndexWith.impl.At]
+// CHECK:STDOUT:   %impl.elem1: %.7d9 = impl_witness_access constants.%IndexWith.impl_witness, element1 [concrete = constants.%tuple.type.as.IndexWith.impl.At]
 // CHECK:STDOUT:   %bound_method: <bound method> = bound_method %s.ref, %impl.elem1
-// CHECK:STDOUT:   %tuple.type.as.IndexWith.impl.At.call: init %i32 = call %bound_method(%s.ref, %int_0)
+// CHECK:STDOUT:   %tuple.type.as.IndexWith.impl.At.call: init %C = call %bound_method(%s.ref, %int_0)
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 1 - 0
toolchain/diagnostics/diagnostic_kind.def

@@ -332,6 +332,7 @@ CARBON_DIAGNOSTIC_KIND(ImplAsNonFacetType)
 CARBON_DIAGNOSTIC_KIND(ImplAsOutsideClass)
 CARBON_DIAGNOSTIC_KIND(ImplAssociatedConstantNeedsValue)
 CARBON_DIAGNOSTIC_KIND(ImplFunctionWithNonFunction)
+CARBON_DIAGNOSTIC_KIND(ImplIsOrphan)
 CARBON_DIAGNOSTIC_KIND(ImplMissingDefinition)
 CARBON_DIAGNOSTIC_KIND(ImplMissingFunction)
 CARBON_DIAGNOSTIC_KIND(ImplPreviousDefinition)