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

Basic support for argument deduction in generic `impl`s. (#4380)

Refactor the current function call deduction logic to make it reusable.
Call into it from `impl` deduction. Also build a generic region for the
definition portion of a generic `impl` and substitute into it before
accessing the witness in a specific `impl`.

This is enough to get simple uses of generic `impl`s to work. The main
blocker for more complex cases is that we have very little support for
non-trivial deduction, so while we can deduce `forall [T:! type] T as
I`, we can't deduce `forall [T:! type] C as I(T)` yet.
Richard Smith 1 год назад
Родитель
Сommit
9fadfb5e82

+ 193 - 91
toolchain/check/deduce.cpp

@@ -75,6 +75,58 @@ class DeductionWorklist {
   Context& context_;
   llvm::SmallVector<PendingDeduction> deductions_;
 };
+
+// State that is tracked throughout the deduction process.
+class DeductionContext {
+ public:
+  // Preparse to perform deduction. If an enclosing specific is provided, adds
+  // the arguments from the given specific as known arguments that will not be
+  // deduced.
+  DeductionContext(Context& context, SemIR::LocId loc_id,
+                   SemIR::GenericId generic_id,
+                   SemIR::SpecificId enclosing_specific_id, bool diagnose);
+
+  auto context() const -> Context& { return *context_; }
+
+  // Adds a pending deduction of `param` from `arg`. `needs_substitution`
+  // indicates whether we need to substitute known generic parameters into
+  // `param`.
+  template <typename ParamT, typename ArgT>
+  auto Add(ParamT param, ArgT arg, bool needs_substitution) -> void {
+    worklist_.Add(param, arg, needs_substitution);
+  }
+
+  // Same as `Add` but for an array or block of operands.
+  template <typename ParamT, typename ArgT>
+  auto AddAll(ParamT param, ArgT arg, bool needs_substitution) -> void {
+    worklist_.AddAll(param, arg, needs_substitution);
+  }
+
+  // Performs all deductions in the deduction worklist. Returns whether
+  // deduction succeeded.
+  auto Deduce() -> bool;
+
+  // Returns whether every generic parameter has a corresponding deduced generic
+  // argument. If not, issues a suitable diagnostic.
+  auto CheckDeductionIsComplete() -> bool;
+
+  // Forms a specific corresponding to the deduced generic with the deduced
+  // argument list. Must not be called before deduction is complete.
+  auto MakeSpecific() -> SemIR::SpecificId;
+
+ private:
+  Context* context_;
+  SemIR::LocId loc_id_;
+  SemIR::GenericId generic_id_;
+  bool diagnose_;
+
+  DeductionWorklist worklist_;
+
+  llvm::SmallVector<SemIR::InstId> result_arg_ids_;
+  llvm::SmallVector<Substitution> substitutions_;
+  SemIR::CompileTimeBindIndex first_deduced_index_;
+};
+
 }  // namespace
 
 static auto NoteGenericHere(Context& context, SemIR::GenericId generic_id,
@@ -84,121 +136,127 @@ static auto NoteGenericHere(Context& context, SemIR::GenericId generic_id,
   diag.Note(context.generics().Get(generic_id).decl_id, DeductionGenericHere);
 }
 
-auto DeduceGenericCallArguments(
-    Context& context, SemIR::LocId loc_id, SemIR::GenericId generic_id,
-    SemIR::SpecificId enclosing_specific_id,
-    [[maybe_unused]] SemIR::InstBlockId implicit_params_id,
-    SemIR::InstBlockId params_id, [[maybe_unused]] SemIR::InstId self_id,
-    llvm::ArrayRef<SemIR::InstId> arg_ids) -> SemIR::SpecificId {
-  DeductionWorklist worklist(context);
+DeductionContext::DeductionContext(Context& context, SemIR::LocId loc_id,
+                                   SemIR::GenericId generic_id,
+                                   SemIR::SpecificId enclosing_specific_id,
+                                   bool diagnose)
+    : context_(&context),
+      loc_id_(loc_id),
+      generic_id_(generic_id),
+      diagnose_(diagnose),
+      worklist_(context),
+      first_deduced_index_(0) {
+  CARBON_CHECK(generic_id.is_valid(),
+               "Performing deduction for non-generic entity");
 
-  llvm::SmallVector<SemIR::InstId> result_arg_ids;
-  llvm::SmallVector<Substitution> substitutions;
+  // Initialize the deduced arguments to Invalid.
+  result_arg_ids_.resize(
+      context.inst_blocks()
+          .Get(context.generics().Get(generic_id_).bindings_id)
+          .size(),
+      SemIR::InstId::Invalid);
 
-  // Copy any outer generic arguments from the specified instance and prepare to
-  // substitute them into the function declaration.
   if (enclosing_specific_id.is_valid()) {
+    // Copy any outer generic arguments from the specified instance and prepare
+    // to substitute them into the function declaration.
     auto args = context.inst_blocks().Get(
         context.specifics().Get(enclosing_specific_id).args_id);
-    result_arg_ids.assign(args.begin(), args.end());
+    std::copy(args.begin(), args.end(), result_arg_ids_.begin());
 
-    // TODO: Subst is linear in the length of the substitutions list. Change it
-    // so we can pass in an array mapping indexes to substitutions instead.
-    substitutions.reserve(args.size());
+    // TODO: Subst is linear in the length of the substitutions list. Change
+    // it so we can pass in an array mapping indexes to substitutions instead.
+    substitutions_.reserve(args.size());
     for (auto [i, subst_inst_id] : llvm::enumerate(args)) {
-      substitutions.push_back(
+      substitutions_.push_back(
           {.bind_id = SemIR::CompileTimeBindIndex(i),
            .replacement_id = context.constant_values().Get(subst_inst_id)});
     }
+    first_deduced_index_ = SemIR::CompileTimeBindIndex(args.size());
   }
-  auto first_deduced_index = SemIR::CompileTimeBindIndex(result_arg_ids.size());
-
-  // Initialize the deduced arguments to Invalid.
-  result_arg_ids.resize(context.inst_blocks()
-                            .Get(context.generics().Get(generic_id).bindings_id)
-                            .size(),
-                        SemIR::InstId::Invalid);
-
-  // Prepare to perform deduction of the explicit parameters against their
-  // arguments.
-  // TODO: Also perform deduction for type of self.
-  worklist.AddAll(params_id, arg_ids, /*needs_substitution=*/true);
+}
 
-  while (!worklist.Done()) {
-    auto [param_id, arg_id, needs_substitution] = worklist.PopNext();
+auto DeductionContext::Deduce() -> bool {
+  while (!worklist_.Done()) {
+    auto [param_id, arg_id, needs_substitution] = worklist_.PopNext();
 
     // If the parameter has a symbolic type, deduce against that.
-    auto param_type_id = context.insts().Get(param_id).type_id();
+    auto param_type_id = context().insts().Get(param_id).type_id();
     if (param_type_id.AsConstantId().is_symbolic()) {
-      worklist.Add(
-          context.types().GetInstId(param_type_id),
-          context.types().GetInstId(context.insts().Get(arg_id).type_id()),
+      Add(context().types().GetInstId(param_type_id),
+          context().types().GetInstId(context().insts().Get(arg_id).type_id()),
           needs_substitution);
     } else {
       // The argument needs to have the same type as the parameter.
+      // TODO: Suppress diagnostics here if diagnose_ is false.
       DiagnosticAnnotationScope annotate_diagnostics(
-          &context.emitter(), [&](auto& builder) {
-            if (auto param = context.insts().TryGetAs<SemIR::BindSymbolicName>(
-                    param_id)) {
+          &context().emitter(), [&](auto& builder) {
+            if (auto param =
+                    context().insts().TryGetAs<SemIR::BindSymbolicName>(
+                        param_id)) {
               CARBON_DIAGNOSTIC(
                   InitializingGenericParam, Note,
                   "initializing generic parameter `{0}` declared here",
                   SemIR::NameId);
               builder.Note(
                   param_id, InitializingGenericParam,
-                  context.entity_names().Get(param->entity_name_id).name_id);
+                  context().entity_names().Get(param->entity_name_id).name_id);
             }
           });
-      arg_id = ConvertToValueOfType(context, loc_id, arg_id, param_type_id);
+      arg_id = ConvertToValueOfType(context(), loc_id_, arg_id, param_type_id);
       if (arg_id == SemIR::InstId::BuiltinError) {
-        return SemIR::SpecificId::Invalid;
+        return false;
       }
     }
 
     // If the parameter is a symbolic constant, deduce against it.
-    auto param_const_id = context.constant_values().Get(param_id);
+    auto param_const_id = context().constant_values().Get(param_id);
     if (!param_const_id.is_valid() || !param_const_id.is_symbolic()) {
       continue;
     }
 
     // If we've not yet substituted into the parameter, do so now.
     if (needs_substitution) {
-      param_const_id = SubstConstant(context, param_const_id, substitutions);
+      param_const_id = SubstConstant(context(), param_const_id, substitutions_);
       if (!param_const_id.is_valid() || !param_const_id.is_symbolic()) {
         continue;
       }
       needs_substitution = false;
     }
 
-    CARBON_KIND_SWITCH(context.insts().Get(context.constant_values().GetInstId(
-                           param_const_id))) {
+    CARBON_KIND_SWITCH(context().insts().Get(
+                           context().constant_values().GetInstId(
+                               param_const_id))) {
       // Deducing a symbolic binding from an argument with a constant value
       // deduces the binding as having that constant value.
       case CARBON_KIND(SemIR::BindSymbolicName bind): {
-        auto& entity_name = context.entity_names().Get(bind.entity_name_id);
+        auto& entity_name = context().entity_names().Get(bind.entity_name_id);
         auto index = entity_name.bind_index;
-        if (index.is_valid() && index >= first_deduced_index) {
-          CARBON_CHECK(static_cast<size_t>(index.index) < result_arg_ids.size(),
-                       "Deduced value for unexpected index {0}; expected to "
-                       "deduce {1} arguments.",
-                       index, result_arg_ids.size());
+        if (index.is_valid() && index >= first_deduced_index_) {
+          CARBON_CHECK(
+              static_cast<size_t>(index.index) < result_arg_ids_.size(),
+              "Deduced value for unexpected index {0}; expected to "
+              "deduce {1} arguments.",
+              index, result_arg_ids_.size());
           auto arg_const_inst_id =
-              context.constant_values().GetConstantInstId(arg_id);
+              context().constant_values().GetConstantInstId(arg_id);
           if (arg_const_inst_id.is_valid()) {
-            if (result_arg_ids[index.index].is_valid() &&
-                result_arg_ids[index.index] != arg_const_inst_id) {
-              // TODO: Include the two different deduced values.
-              CARBON_DIAGNOSTIC(DeductionInconsistent, Error,
-                                "inconsistent deductions for value of generic "
-                                "parameter `{0}`",
-                                SemIR::NameId);
-              auto diag = context.emitter().Build(loc_id, DeductionInconsistent,
-                                                  entity_name.name_id);
-              NoteGenericHere(context, generic_id, diag);
-              diag.Emit();
-              return SemIR::SpecificId::Invalid;
+            if (result_arg_ids_[index.index].is_valid() &&
+                result_arg_ids_[index.index] != arg_const_inst_id) {
+              if (diagnose_) {
+                // TODO: Include the two different deduced values.
+                CARBON_DIAGNOSTIC(
+                    DeductionInconsistent, Error,
+                    "inconsistent deductions for value of generic "
+                    "parameter `{0}`",
+                    SemIR::NameId);
+                auto diag = context().emitter().Build(
+                    loc_id_, DeductionInconsistent, entity_name.name_id);
+                NoteGenericHere(context(), generic_id_, diag);
+                diag.Emit();
+              }
+              return false;
             }
-            result_arg_ids[index.index] = arg_const_inst_id;
+            result_arg_ids_[index.index] = arg_const_inst_id;
           }
         }
         break;
@@ -211,46 +269,90 @@ auto DeduceGenericCallArguments(
     }
   }
 
+  return true;
+}
+
+auto DeductionContext::CheckDeductionIsComplete() -> bool {
   // Check we deduced an argument value for every parameter.
   for (auto [i, deduced_arg_id] :
-       llvm::enumerate(llvm::ArrayRef(result_arg_ids)
-                           .drop_front(first_deduced_index.index))) {
+       llvm::enumerate(llvm::ArrayRef(result_arg_ids_)
+                           .drop_front(first_deduced_index_.index))) {
     if (!deduced_arg_id.is_valid()) {
-      auto binding_index = first_deduced_index.index + i;
-      auto binding_id = context.inst_blocks().Get(
-          context.generics().Get(generic_id).bindings_id)[binding_index];
-      auto entity_name_id =
-          context.insts().GetAs<SemIR::AnyBindName>(binding_id).entity_name_id;
-      CARBON_DIAGNOSTIC(DeductionIncomplete, Error,
-                        "cannot deduce value for generic parameter `{0}`",
-                        SemIR::NameId);
-      auto diag = context.emitter().Build(
-          loc_id, DeductionIncomplete,
-          context.entity_names().Get(entity_name_id).name_id);
-      NoteGenericHere(context, generic_id, diag);
-      diag.Emit();
-      return SemIR::SpecificId::Invalid;
+      if (diagnose_) {
+        auto binding_index = first_deduced_index_.index + i;
+        auto binding_id = context().inst_blocks().Get(
+            context().generics().Get(generic_id_).bindings_id)[binding_index];
+        auto entity_name_id = context()
+                                  .insts()
+                                  .GetAs<SemIR::AnyBindName>(binding_id)
+                                  .entity_name_id;
+        CARBON_DIAGNOSTIC(DeductionIncomplete, Error,
+                          "cannot deduce value for generic parameter `{0}`",
+                          SemIR::NameId);
+        auto diag = context().emitter().Build(
+            loc_id_, DeductionIncomplete,
+            context().entity_names().Get(entity_name_id).name_id);
+        NoteGenericHere(context(), generic_id_, diag);
+        diag.Emit();
+      }
+      return false;
     }
   }
 
+  return true;
+}
+
+auto DeductionContext::MakeSpecific() -> SemIR::SpecificId {
   // TODO: Convert the deduced values to the types of the bindings.
 
-  return MakeSpecific(context, generic_id,
-                      context.inst_blocks().AddCanonical(result_arg_ids));
+  return Check::MakeSpecific(
+      context(), generic_id_,
+      context().inst_blocks().AddCanonical(result_arg_ids_));
+}
+
+auto DeduceGenericCallArguments(
+    Context& context, SemIR::LocId loc_id, SemIR::GenericId generic_id,
+    SemIR::SpecificId enclosing_specific_id,
+    [[maybe_unused]] SemIR::InstBlockId implicit_params_id,
+    SemIR::InstBlockId params_id, [[maybe_unused]] SemIR::InstId self_id,
+    llvm::ArrayRef<SemIR::InstId> arg_ids) -> SemIR::SpecificId {
+  DeductionContext deduction(context, loc_id, generic_id, enclosing_specific_id,
+                             /*diagnose=*/true);
+
+  // Prepare to perform deduction of the explicit parameters against their
+  // arguments.
+  // TODO: Also perform deduction for type of self.
+  deduction.AddAll(params_id, arg_ids, /*needs_substitution=*/true);
+
+  if (!deduction.Deduce() || !deduction.CheckDeductionIsComplete()) {
+    return SemIR::SpecificId::Invalid;
+  }
+
+  return deduction.MakeSpecific();
 }
 
 // Deduces the impl arguments to use in a use of a parameterized impl. Returns
 // `Invalid` if deduction fails.
-auto DeduceImplArguments(Context& context, const SemIR::Impl& impl,
-                         SemIR::ConstantId self_id,
+auto DeduceImplArguments(Context& context, SemIR::LocId loc_id,
+                         const SemIR::Impl& impl, SemIR::ConstantId self_id,
                          SemIR::ConstantId constraint_id) -> SemIR::SpecificId {
-  CARBON_CHECK(impl.generic_id.is_valid(),
-               "Performing deduction for non-generic impl");
-  // TODO: This is a placeholder. Implement deduction.
-  static_cast<void>(context);
-  static_cast<void>(self_id);
-  static_cast<void>(constraint_id);
-  return SemIR::SpecificId::Invalid;
+  DeductionContext deduction(
+      context, loc_id, impl.generic_id,
+      /*enclosing_specific_id=*/SemIR::SpecificId::Invalid,
+      /*diagnose=*/false);
+
+  // Prepare to perform deduction of the type and interface.
+  deduction.Add(impl.self_id, context.constant_values().GetInstId(self_id),
+                /*needs_substitution=*/false);
+  deduction.Add(impl.constraint_id,
+                context.constant_values().GetInstId(constraint_id),
+                /*needs_substitution=*/false);
+
+  if (!deduction.Deduce() || !deduction.CheckDeductionIsComplete()) {
+    return SemIR::SpecificId::Invalid;
+  }
+
+  return deduction.MakeSpecific();
 }
 
 }  // namespace Carbon::Check

+ 2 - 2
toolchain/check/deduce.h

@@ -22,8 +22,8 @@ auto DeduceGenericCallArguments(Context& context, SemIR::LocId loc_id,
 
 // Deduces the impl arguments to use in a use of a parameterized impl. Returns
 // `Invalid` if deduction fails.
-auto DeduceImplArguments(Context& context, const SemIR::Impl& impl,
-                         SemIR::ConstantId self_id,
+auto DeduceImplArguments(Context& context, SemIR::LocId loc_id,
+                         const SemIR::Impl& impl, SemIR::ConstantId self_id,
                          SemIR::ConstantId constraint_id) -> SemIR::SpecificId;
 
 }  // namespace Carbon::Check

+ 9 - 4
toolchain/check/handle_impl.cpp

@@ -359,7 +359,10 @@ auto HandleParseNode(Context& context, Parse::ImplDefinitionStartId node_id)
         context.decl_name_stack().PeekParentScopeId());
   }
 
-  context.scope_stack().Push(impl_decl_id, impl_info.scope_id);
+  context.scope_stack().Push(
+      impl_decl_id, impl_info.scope_id,
+      context.generics().GetSelfSpecific(impl_info.generic_id));
+  StartGenericDefinition(context);
 
   context.inst_block_stack().Push();
   context.node_stack().Push(node_id, impl_id);
@@ -382,11 +385,13 @@ auto HandleParseNode(Context& context, Parse::ImplDefinitionId /*node_id*/)
   auto impl_id =
       context.node_stack().Pop<Parse::NodeKind::ImplDefinitionStart>();
 
-  if (!context.impls().Get(impl_id).is_defined()) {
-    context.impls().Get(impl_id).witness_id =
-        BuildImplWitness(context, impl_id);
+  auto& impl_info = context.impls().Get(impl_id);
+  if (!impl_info.is_defined()) {
+    impl_info.witness_id = BuildImplWitness(context, impl_id);
   }
 
+  FinishGenericDefinition(context, impl_info.generic_id);
+
   context.inst_block_stack().Pop();
   // The decl_name_stack and scopes are popped by `ProcessNodeIds`.
   return true;

+ 12 - 5
toolchain/check/member_access.cpp

@@ -11,6 +11,7 @@
 #include "toolchain/check/context.h"
 #include "toolchain/check/convert.h"
 #include "toolchain/check/deduce.h"
+#include "toolchain/check/generic.h"
 #include "toolchain/check/import_ref.h"
 #include "toolchain/diagnostics/diagnostic_emitter.h"
 #include "toolchain/sem_ir/generic.h"
@@ -175,7 +176,7 @@ static auto ScopeNeedsImplLookup(Context& context, LookupScope scope) -> bool {
 // Given a type and an interface, searches for an impl that describes how that
 // type implements that interface, and returns the corresponding witness.
 // Returns an invalid InstId if no matching impl is found.
-static auto LookupInterfaceWitness(Context& context,
+static auto LookupInterfaceWitness(Context& context, SemIR::LocId loc_id,
                                    SemIR::ConstantId type_const_id,
                                    SemIR::ConstantId interface_const_id)
     -> SemIR::InstId {
@@ -185,8 +186,8 @@ static auto LookupInterfaceWitness(Context& context,
   for (const auto& impl : context.impls().array_ref()) {
     auto specific_id = SemIR::SpecificId::Invalid;
     if (impl.generic_id.is_valid()) {
-      specific_id =
-          DeduceImplArguments(context, impl, type_const_id, interface_const_id);
+      specific_id = DeduceImplArguments(context, loc_id, impl, type_const_id,
+                                        interface_const_id);
       if (!specific_id.is_valid()) {
         continue;
       }
@@ -210,6 +211,11 @@ static auto LookupInterfaceWitness(Context& context,
       return SemIR::InstId::Invalid;
     }
     LoadImportRef(context, impl.witness_id);
+    if (specific_id.is_valid()) {
+      // We need a definition of the specific `impl` so we can access its
+      // witness.
+      ResolveSpecificDefinition(context, specific_id);
+    }
     return context.constant_values().GetInstId(
         SemIR::GetConstantValueInSpecific(context.sem_ir(), specific_id,
                                           impl.witness_id));
@@ -227,8 +233,9 @@ static auto PerformImplLookup(
   auto interface_type =
       context.types().GetAs<SemIR::InterfaceType>(assoc_type.interface_type_id);
   auto& interface = context.interfaces().Get(interface_type.interface_id);
-  auto witness_id = LookupInterfaceWitness(
-      context, type_const_id, assoc_type.interface_type_id.AsConstantId());
+  auto witness_id =
+      LookupInterfaceWitness(context, loc_id, type_const_id,
+                             assoc_type.interface_type_id.AsConstantId());
   if (!witness_id.is_valid()) {
     if (missing_impl_diagnoser) {
       // TODO: Pass in the expression whose type we are printing.

+ 20 - 5
toolchain/check/testdata/impl/fail_extend_impl_forall.carbon

@@ -35,9 +35,9 @@ class C {
 // CHECK:STDOUT:   %.2: type = assoc_entity_type %GenericInterface.type.2, %F.type.1 [symbolic]
 // CHECK:STDOUT:   %.3: %.2 = assoc_entity element0, @GenericInterface.%F.decl [symbolic]
 // CHECK:STDOUT:   %C: type = class_type @C [template]
-// CHECK:STDOUT:   %F.type.2: type = fn_type @F.2 [template]
-// CHECK:STDOUT:   %F.2: %F.type.2 = struct_value () [template]
-// CHECK:STDOUT:   %.4: <witness> = interface_witness (%F.2) [template]
+// CHECK:STDOUT:   %F.type.2: type = fn_type @F.2, @impl(%T) [symbolic]
+// CHECK:STDOUT:   %F.2: %F.type.2 = struct_value () [symbolic]
+// CHECK:STDOUT:   %.4: <witness> = interface_witness (%F.2) [symbolic]
 // CHECK:STDOUT:   %.5: type = struct_type {} [template]
 // CHECK:STDOUT:   %.6: <witness> = complete_type_witness %.5 [template]
 // CHECK:STDOUT: }
@@ -104,15 +104,20 @@ class C {
 // CHECK:STDOUT:   %T.1: type = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T)]
 // CHECK:STDOUT:   %GenericInterface.type.1: type = interface_type @GenericInterface, @GenericInterface(%T.1) [symbolic = %GenericInterface.type.1 (constants.%GenericInterface.type.2)]
 // CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %F.type: type = fn_type @F.2, @impl(%T.1) [symbolic = %F.type (constants.%F.type.2)]
+// CHECK:STDOUT:   %F: @impl.%F.type (%F.type.2) = struct_value () [symbolic = %F (constants.%F.2)]
+// CHECK:STDOUT:   %.1: <witness> = interface_witness (%F) [symbolic = %.1 (constants.%.4)]
+// CHECK:STDOUT:
 // CHECK:STDOUT:   impl: %Self.ref as %GenericInterface.type.loc19 {
-// CHECK:STDOUT:     %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {
+// CHECK:STDOUT:     %F.decl: @impl.%F.type (%F.type.2) = fn_decl @F.2 [symbolic = @impl.%F (constants.%F.2)] {
 // CHECK:STDOUT:       %x.patt: @F.2.%T (%T) = binding_pattern x
 // CHECK:STDOUT:     } {
 // CHECK:STDOUT:       %T.ref: type = name_ref T, @impl.%T.loc19 [symbolic = %T (constants.%T)]
 // CHECK:STDOUT:       %x.param: @F.2.%T (%T) = param x, runtime_param0
 // CHECK:STDOUT:       %x: @F.2.%T (%T) = bind_name x, %x.param
 // CHECK:STDOUT:     }
-// CHECK:STDOUT:     %.loc19: <witness> = interface_witness (%F.decl) [template = constants.%.4]
+// CHECK:STDOUT:     %.loc19: <witness> = interface_witness (%F.decl) [symbolic = %.1 (constants.%.4)]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   !members:
 // CHECK:STDOUT:     .F = %F.decl
@@ -182,6 +187,11 @@ class C {
 // CHECK:STDOUT: specific @impl(constants.%T) {
 // CHECK:STDOUT:   %T.1 => constants.%T
 // CHECK:STDOUT:   %GenericInterface.type.1 => constants.%GenericInterface.type.2
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %F.type => constants.%F.type.2
+// CHECK:STDOUT:   %F => constants.%F.2
+// CHECK:STDOUT:   %.1 => constants.%.4
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @F.2(constants.%T) {
@@ -192,3 +202,8 @@ class C {
 // CHECK:STDOUT:   %T => constants.%T
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl(@impl.%T.1) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT:   %GenericInterface.type.1 => constants.%GenericInterface.type.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:

+ 19 - 5
toolchain/check/testdata/impl/impl_forall.carbon

@@ -27,9 +27,9 @@ impl forall [T:! type] T as Simple {
 // CHECK:STDOUT:   %.2: type = assoc_entity_type %Simple.type, %F.type.1 [template]
 // CHECK:STDOUT:   %.3: %.2 = assoc_entity element0, @Simple.%F.decl [template]
 // CHECK:STDOUT:   %T: type = bind_symbolic_name T, 0 [symbolic]
-// CHECK:STDOUT:   %F.type.2: type = fn_type @F.2 [template]
-// CHECK:STDOUT:   %F.2: %F.type.2 = struct_value () [template]
-// CHECK:STDOUT:   %.4: <witness> = interface_witness (%F.2) [template]
+// CHECK:STDOUT:   %F.type.2: type = fn_type @F.2, @impl(%T) [symbolic]
+// CHECK:STDOUT:   %F.2: %F.type.2 = struct_value () [symbolic]
+// CHECK:STDOUT:   %.4: <witness> = interface_witness (%F.2) [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -76,9 +76,14 @@ impl forall [T:! type] T as Simple {
 // CHECK:STDOUT: generic impl @impl(%T.loc15: type) {
 // CHECK:STDOUT:   %T.1: type = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T)]
 // CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %F.type: type = fn_type @F.2, @impl(%T.1) [symbolic = %F.type (constants.%F.type.2)]
+// CHECK:STDOUT:   %F: @impl.%F.type (%F.type.2) = struct_value () [symbolic = %F (constants.%F.2)]
+// CHECK:STDOUT:   %.1: <witness> = interface_witness (%F) [symbolic = %.1 (constants.%.4)]
+// CHECK:STDOUT:
 // CHECK:STDOUT:   impl: %T.ref as %Simple.ref {
-// CHECK:STDOUT:     %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {} {}
-// CHECK:STDOUT:     %.loc15: <witness> = interface_witness (%F.decl) [template = constants.%.4]
+// CHECK:STDOUT:     %F.decl: @impl.%F.type (%F.type.2) = fn_decl @F.2 [symbolic = @impl.%F (constants.%F.2)] {} {}
+// CHECK:STDOUT:     %.loc15: <witness> = interface_witness (%F.decl) [symbolic = %.1 (constants.%.4)]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   !members:
 // CHECK:STDOUT:     .F = %F.decl
@@ -104,9 +109,18 @@ impl forall [T:! type] T as Simple {
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @impl(constants.%T) {
 // CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %F.type => constants.%F.type.2
+// CHECK:STDOUT:   %F => constants.%F.2
+// CHECK:STDOUT:   %.1 => constants.%.4
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @F.2(constants.%T) {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @F.1(constants.%T) {}
 // CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl(@impl.%T.1) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:

+ 1189 - 0
toolchain/check/testdata/impl/lookup/generic.carbon

@@ -0,0 +1,1189 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// AUTOUPDATE
+// TIP: To test this file alone, run:
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/impl/lookup/generic.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/impl/lookup/generic.carbon
+
+// --- deduced_type.carbon
+
+library "[[@TEST_NAME]]";
+
+interface HasF {
+  fn F();
+}
+
+impl forall [T:! type] T as HasF {
+  fn F() {}
+}
+
+fn G(x: {}) {
+  x.(HasF.F)();
+}
+
+// --- deduced_type_subst.carbon
+
+library "[[@TEST_NAME]]";
+
+interface HasF {
+  fn F[self: Self]() -> Self;
+}
+
+impl forall [T:! type] T as HasF {
+  fn F[self: Self]() -> T { return self; }
+}
+
+fn G(x: {}) -> {} {
+  return x.(HasF.F)();
+}
+
+// --- fail_todo_deduced_type_argument.carbon
+
+library "[[@TEST_NAME]]";
+
+interface HasF {
+  fn F();
+}
+
+class C(T:! type) {}
+
+impl forall [T:! type] C(T) as HasF {
+  fn F() {}
+}
+
+fn G(x: C({})) {
+  // TODO: Implement support for deducing T in C(T).
+  // CHECK:STDERR: fail_todo_deduced_type_argument.carbon:[[@LINE+4]]:3: error: cannot access member of interface `HasF` in type `C` that does not implement that interface
+  // CHECK:STDERR:   x.(HasF.F)();
+  // CHECK:STDERR:   ^~~~~~~~~~
+  // CHECK:STDERR:
+  x.(HasF.F)();
+}
+
+// --- fail_todo_deduced_interface_argument.carbon
+
+library "[[@TEST_NAME]]";
+
+interface HasF(T:! type) {
+  fn F();
+}
+
+impl forall [T:! type] {} as HasF(T) {
+  fn F() {}
+}
+
+fn G(x: {}) {
+  // TODO: Implement support for deducing T in HasF(T).
+  // CHECK:STDERR: fail_todo_deduced_interface_argument.carbon:[[@LINE+4]]:3: error: cannot access member of interface `HasF` in type `{}` that does not implement that interface
+  // CHECK:STDERR:   x.(HasF({}).F)();
+  // CHECK:STDERR:   ^~~~~~~~~~~~~~
+  // CHECK:STDERR:
+  x.(HasF({}).F)();
+}
+
+// --- fail_incomplete_deduction.carbon
+
+library "[[@TEST_NAME]]";
+
+interface HasF {
+  fn F();
+}
+
+// TODO: Reject this declaration because U cannot be deduced.
+impl forall [T:! type, U:! type] T as HasF {
+  fn F() {}
+}
+
+fn G(x: {}) {
+  // TODO: It'd be nice to include a note here saying that deduction failed because
+  // we couldn't deduce a value for 'U'.
+  // CHECK:STDERR: fail_incomplete_deduction.carbon:[[@LINE+4]]:3: error: cannot access member of interface `HasF` in type `{}` that does not implement that interface
+  // CHECK:STDERR:   x.(HasF.F)();
+  // CHECK:STDERR:   ^~~~~~~~~~
+  // CHECK:STDERR:
+  x.(HasF.F)();
+}
+
+// --- fail_inconsistent_deduction.carbon
+
+library "[[@TEST_NAME]]";
+
+interface HasF(T:! type) {
+  fn F();
+}
+
+impl forall [T:! type] T as HasF(T) {
+  fn F() {}
+}
+
+class A {}
+class B {}
+
+fn G(x: A) {
+  // TODO: It'd be nice to include a note here saying that deduction failed because
+  // we deduced two different values for `T`.
+  // CHECK:STDERR: fail_inconsistent_deduction.carbon:[[@LINE+3]]:3: error: cannot access member of interface `HasF` in type `A` that does not implement that interface
+  // CHECK:STDERR:   x.(HasF(B).F)();
+  // CHECK:STDERR:   ^~~~~~~~~~~~~
+  x.(HasF(B).F)();
+}
+
+// CHECK:STDOUT: --- deduced_type.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %HasF.type: type = interface_type @HasF [template]
+// CHECK:STDOUT:   %Self: %HasF.type = bind_symbolic_name Self, 0 [symbolic]
+// CHECK:STDOUT:   %F.type.1: type = fn_type @F.1 [template]
+// CHECK:STDOUT:   %.1: type = tuple_type () [template]
+// CHECK:STDOUT:   %F.1: %F.type.1 = struct_value () [template]
+// CHECK:STDOUT:   %.2: type = assoc_entity_type %HasF.type, %F.type.1 [template]
+// CHECK:STDOUT:   %.3: %.2 = assoc_entity element0, @HasF.%F.decl [template]
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T, 0 [symbolic]
+// CHECK:STDOUT:   %F.type.2: type = fn_type @F.2, @impl(%T) [symbolic]
+// CHECK:STDOUT:   %F.2: %F.type.2 = struct_value () [symbolic]
+// CHECK:STDOUT:   %.4: <witness> = interface_witness (%F.2) [symbolic]
+// CHECK:STDOUT:   %.5: type = struct_type {} [template]
+// CHECK:STDOUT:   %G.type: type = fn_type @G [template]
+// CHECK:STDOUT:   %G: %G.type = struct_value () [template]
+// CHECK:STDOUT:   %F.type.3: type = fn_type @F.2, @impl(%.5) [template]
+// CHECK:STDOUT:   %F.3: %F.type.3 = struct_value () [template]
+// CHECK:STDOUT:   %.6: <witness> = interface_witness (%F.3) [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/operators
+// CHECK:STDOUT:     import Core//prelude/types
+// CHECK:STDOUT:     import Core//prelude/operators/arithmetic
+// CHECK:STDOUT:     import Core//prelude/operators/as
+// CHECK:STDOUT:     import Core//prelude/operators/bitwise
+// CHECK:STDOUT:     import Core//prelude/operators/comparison
+// CHECK:STDOUT:     import Core//prelude/types/bool
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .HasF = %HasF.decl
+// CHECK:STDOUT:     .G = %G.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %HasF.decl: type = interface_decl @HasF [template = constants.%HasF.type] {} {}
+// CHECK:STDOUT:   impl_decl @impl [template] {
+// CHECK:STDOUT:     %T.patt: type = symbolic_binding_pattern T, 0
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %T.param: type = param T, runtime_param<invalid>
+// CHECK:STDOUT:     %T.loc8: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:     %T.ref: type = name_ref T, %T.loc8 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:     %HasF.ref: type = name_ref HasF, file.%HasF.decl [template = constants.%HasF.type]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %G.decl: %G.type = fn_decl @G [template = constants.%G] {
+// CHECK:STDOUT:     %x.patt: %.5 = binding_pattern x
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %.loc12_10.1: %.5 = struct_literal ()
+// CHECK:STDOUT:     %.loc12_10.2: type = converted %.loc12_10.1, constants.%.5 [template = constants.%.5]
+// CHECK:STDOUT:     %x.param: %.5 = param x, runtime_param0
+// CHECK:STDOUT:     %x: %.5 = bind_name x, %x.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @HasF {
+// CHECK:STDOUT:   %Self: %HasF.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:   %F.decl: %F.type.1 = fn_decl @F.1 [template = constants.%F.1] {} {}
+// CHECK:STDOUT:   %.loc5: %.2 = assoc_entity element0, %F.decl [template = constants.%.3]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   .F = %.loc5
+// CHECK:STDOUT:   witness = (%F.decl)
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic impl @impl(%T.loc8: type) {
+// CHECK:STDOUT:   %T.1: type = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %F.type: type = fn_type @F.2, @impl(%T.1) [symbolic = %F.type (constants.%F.type.2)]
+// CHECK:STDOUT:   %F: @impl.%F.type (%F.type.2) = struct_value () [symbolic = %F (constants.%F.2)]
+// CHECK:STDOUT:   %.1: <witness> = interface_witness (%F) [symbolic = %.1 (constants.%.4)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   impl: %T.ref as %HasF.ref {
+// CHECK:STDOUT:     %F.decl: @impl.%F.type (%F.type.2) = fn_decl @F.2 [symbolic = @impl.%F (constants.%F.2)] {} {}
+// CHECK:STDOUT:     %.loc8: <witness> = interface_witness (%F.decl) [symbolic = %.1 (constants.%.4)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .F = %F.decl
+// CHECK:STDOUT:     witness = %.loc8
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F.1(@HasF.%Self: %HasF.type) {
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn();
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F.2(@impl.%T.loc8: type) {
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn() {
+// CHECK:STDOUT:   !entry:
+// CHECK:STDOUT:     return
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @G(%x: %.5) {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %x.ref: %.5 = name_ref x, %x
+// CHECK:STDOUT:   %HasF.ref: type = name_ref HasF, file.%HasF.decl [template = constants.%HasF.type]
+// CHECK:STDOUT:   %F.ref: %.2 = name_ref F, @HasF.%.loc5 [template = constants.%.3]
+// CHECK:STDOUT:   %.loc13: %F.type.1 = interface_witness_access constants.%.6, element0 [template = constants.%F.3]
+// CHECK:STDOUT:   %F.call: init %.1 = call %.loc13()
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%Self) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl(constants.%T) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %F.type => constants.%F.type.2
+// CHECK:STDOUT:   %F => constants.%F.2
+// CHECK:STDOUT:   %.1 => constants.%.4
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.2(constants.%T) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%T) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl(@impl.%T.1) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl(constants.%.5) {
+// CHECK:STDOUT:   %T.1 => constants.%.5
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %F.type => constants.%F.type.3
+// CHECK:STDOUT:   %F => constants.%F.3
+// CHECK:STDOUT:   %.1 => constants.%.6
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.2(constants.%.5) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- deduced_type_subst.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %HasF.type: type = interface_type @HasF [template]
+// CHECK:STDOUT:   %Self: %HasF.type = bind_symbolic_name Self, 0 [symbolic]
+// CHECK:STDOUT:   %F.type.1: type = fn_type @F.1 [template]
+// CHECK:STDOUT:   %.1: type = tuple_type () [template]
+// CHECK:STDOUT:   %F.1: %F.type.1 = struct_value () [template]
+// CHECK:STDOUT:   %.2: type = assoc_entity_type %HasF.type, %F.type.1 [template]
+// CHECK:STDOUT:   %.3: %.2 = assoc_entity element0, @HasF.%F.decl [template]
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T, 0 [symbolic]
+// CHECK:STDOUT:   %F.type.2: type = fn_type @F.2, @impl(%T) [symbolic]
+// CHECK:STDOUT:   %F.2: %F.type.2 = struct_value () [symbolic]
+// CHECK:STDOUT:   %.4: <witness> = interface_witness (%F.2) [symbolic]
+// CHECK:STDOUT:   %.5: type = struct_type {} [template]
+// CHECK:STDOUT:   %G.type: type = fn_type @G [template]
+// CHECK:STDOUT:   %G: %G.type = struct_value () [template]
+// CHECK:STDOUT:   %F.type.3: type = fn_type @F.2, @impl(%.5) [template]
+// CHECK:STDOUT:   %F.3: %F.type.3 = struct_value () [template]
+// CHECK:STDOUT:   %.6: <witness> = interface_witness (%F.3) [template]
+// CHECK:STDOUT:   %struct: %.5 = struct_value () [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/operators
+// CHECK:STDOUT:     import Core//prelude/types
+// CHECK:STDOUT:     import Core//prelude/operators/arithmetic
+// CHECK:STDOUT:     import Core//prelude/operators/as
+// CHECK:STDOUT:     import Core//prelude/operators/bitwise
+// CHECK:STDOUT:     import Core//prelude/operators/comparison
+// CHECK:STDOUT:     import Core//prelude/types/bool
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .HasF = %HasF.decl
+// CHECK:STDOUT:     .G = %G.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %HasF.decl: type = interface_decl @HasF [template = constants.%HasF.type] {} {}
+// CHECK:STDOUT:   impl_decl @impl [template] {
+// CHECK:STDOUT:     %T.patt: type = symbolic_binding_pattern T, 0
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %T.param: type = param T, runtime_param<invalid>
+// CHECK:STDOUT:     %T.loc8: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:     %T.ref: type = name_ref T, %T.loc8 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:     %HasF.ref: type = name_ref HasF, file.%HasF.decl [template = constants.%HasF.type]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %G.decl: %G.type = fn_decl @G [template = constants.%G] {
+// CHECK:STDOUT:     %x.patt: %.5 = binding_pattern x
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %.loc12_10.1: %.5 = struct_literal ()
+// CHECK:STDOUT:     %.loc12_10.2: type = converted %.loc12_10.1, constants.%.5 [template = constants.%.5]
+// CHECK:STDOUT:     %x.param: %.5 = param x, runtime_param0
+// CHECK:STDOUT:     %x: %.5 = bind_name x, %x.param
+// CHECK:STDOUT:     %.loc12_17.1: %.5 = struct_literal ()
+// CHECK:STDOUT:     %.loc12_17.2: type = converted %.loc12_17.1, constants.%.5 [template = constants.%.5]
+// CHECK:STDOUT:     %return: ref %.5 = var <return slot>
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @HasF {
+// CHECK:STDOUT:   %Self: %HasF.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:   %F.decl: %F.type.1 = fn_decl @F.1 [template = constants.%F.1] {
+// CHECK:STDOUT:     %self.patt: @F.1.%Self (%Self) = binding_pattern self
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Self.ref.loc5_14: %HasF.type = name_ref Self, @HasF.%Self [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:     %.loc5_14.1: type = facet_type_access %Self.ref.loc5_14 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:     %.loc5_14.2: type = converted %Self.ref.loc5_14, %.loc5_14.1 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:     %self.param: @F.1.%Self (%Self) = param self, runtime_param0
+// CHECK:STDOUT:     %self: @F.1.%Self (%Self) = bind_name self, %self.param
+// CHECK:STDOUT:     %Self.ref.loc5_25: %HasF.type = name_ref Self, @HasF.%Self [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:     %.loc5_25.1: type = facet_type_access %Self.ref.loc5_25 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:     %.loc5_25.2: type = converted %Self.ref.loc5_25, %.loc5_25.1 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:     %return: ref @F.1.%Self (%Self) = var <return slot>
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.loc5: %.2 = assoc_entity element0, %F.decl [template = constants.%.3]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   .F = %.loc5
+// CHECK:STDOUT:   witness = (%F.decl)
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic impl @impl(%T.loc8: type) {
+// CHECK:STDOUT:   %T.1: type = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %F.type: type = fn_type @F.2, @impl(%T.1) [symbolic = %F.type (constants.%F.type.2)]
+// CHECK:STDOUT:   %F: @impl.%F.type (%F.type.2) = struct_value () [symbolic = %F (constants.%F.2)]
+// CHECK:STDOUT:   %.1: <witness> = interface_witness (%F) [symbolic = %.1 (constants.%.4)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   impl: %T.ref as %HasF.ref {
+// CHECK:STDOUT:     %F.decl: @impl.%F.type (%F.type.2) = fn_decl @F.2 [symbolic = @impl.%F (constants.%F.2)] {
+// CHECK:STDOUT:       %self.patt: @F.2.%T (%T) = binding_pattern self
+// CHECK:STDOUT:     } {
+// CHECK:STDOUT:       %Self.ref: type = name_ref Self, @impl.%T.ref [symbolic = %T (constants.%T)]
+// CHECK:STDOUT:       %self.param: @F.2.%T (%T) = param self, runtime_param0
+// CHECK:STDOUT:       %self: @F.2.%T (%T) = bind_name self, %self.param
+// CHECK:STDOUT:       %T.ref: type = name_ref T, @impl.%T.loc8 [symbolic = %T (constants.%T)]
+// CHECK:STDOUT:       %return: ref @F.2.%T (%T) = var <return slot>
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:     %.loc8: <witness> = interface_witness (%F.decl) [symbolic = %.1 (constants.%.4)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .F = %F.decl
+// CHECK:STDOUT:     witness = %.loc8
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F.1(@HasF.%Self: %HasF.type) {
+// CHECK:STDOUT:   %Self: %HasF.type = bind_symbolic_name Self, 0 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn[%self: @F.1.%Self (%Self)]() -> @F.1.%Self (%Self);
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F.2(@impl.%T.loc8: type) {
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn[%self: @F.2.%T (%T)]() -> @F.2.%T (%T) {
+// CHECK:STDOUT:   !entry:
+// CHECK:STDOUT:     %self.ref: @F.2.%T (%T) = name_ref self, %self
+// CHECK:STDOUT:     return %self.ref
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @G(%x: %.5) -> %.5 {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %x.ref: %.5 = name_ref x, %x
+// CHECK:STDOUT:   %HasF.ref: type = name_ref HasF, file.%HasF.decl [template = constants.%HasF.type]
+// CHECK:STDOUT:   %F.ref: %.2 = name_ref F, @HasF.%.loc5 [template = constants.%.3]
+// CHECK:STDOUT:   %.loc13_11.1: %F.type.1 = interface_witness_access constants.%.6, element0 [template = constants.%F.3]
+// CHECK:STDOUT:   %.loc13_11.2: <bound method> = bound_method %x.ref, %.loc13_11.1
+// CHECK:STDOUT:   %F.call: init %.5 = call %.loc13_11.2(%x.ref)
+// CHECK:STDOUT:   %.loc13_20.1: ref %.5 = temporary_storage
+// CHECK:STDOUT:   %.loc13_20.2: ref %.5 = temporary %.loc13_20.1, %F.call
+// CHECK:STDOUT:   %struct: %.5 = struct_value () [template = constants.%struct]
+// CHECK:STDOUT:   %.loc13_22: %.5 = converted %F.call, %struct [template = constants.%struct]
+// CHECK:STDOUT:   return %.loc13_22
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%Self) {
+// CHECK:STDOUT:   %Self => constants.%Self
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl(constants.%T) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %F.type => constants.%F.type.2
+// CHECK:STDOUT:   %F => constants.%F.2
+// CHECK:STDOUT:   %.1 => constants.%.4
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.2(constants.%T) {
+// CHECK:STDOUT:   %T => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%T) {
+// CHECK:STDOUT:   %Self => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl(@impl.%T.1) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl(constants.%.5) {
+// CHECK:STDOUT:   %T.1 => constants.%.5
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %F.type => constants.%F.type.3
+// CHECK:STDOUT:   %F => constants.%F.3
+// CHECK:STDOUT:   %.1 => constants.%.6
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.2(constants.%.5) {
+// CHECK:STDOUT:   %T => constants.%.5
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_todo_deduced_type_argument.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %HasF.type: type = interface_type @HasF [template]
+// CHECK:STDOUT:   %Self: %HasF.type = bind_symbolic_name Self, 0 [symbolic]
+// CHECK:STDOUT:   %F.type.1: type = fn_type @F.1 [template]
+// CHECK:STDOUT:   %.1: type = tuple_type () [template]
+// CHECK:STDOUT:   %F.1: %F.type.1 = struct_value () [template]
+// CHECK:STDOUT:   %.2: type = assoc_entity_type %HasF.type, %F.type.1 [template]
+// CHECK:STDOUT:   %.3: %.2 = assoc_entity element0, @HasF.%F.decl [template]
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T, 0 [symbolic]
+// CHECK:STDOUT:   %C.type: type = generic_class_type @C [template]
+// CHECK:STDOUT:   %C.1: %C.type = struct_value () [template]
+// CHECK:STDOUT:   %C.2: type = class_type @C, @C(%T) [symbolic]
+// CHECK:STDOUT:   %.4: type = struct_type {} [template]
+// CHECK:STDOUT:   %.5: <witness> = complete_type_witness %.4 [template]
+// CHECK:STDOUT:   %F.type.2: type = fn_type @F.2, @impl(%T) [symbolic]
+// CHECK:STDOUT:   %F.2: %F.type.2 = struct_value () [symbolic]
+// CHECK:STDOUT:   %.6: <witness> = interface_witness (%F.2) [symbolic]
+// CHECK:STDOUT:   %C.3: type = class_type @C, @C(%.4) [template]
+// CHECK:STDOUT:   %G.type: type = fn_type @G [template]
+// CHECK:STDOUT:   %G: %G.type = struct_value () [template]
+// CHECK:STDOUT:   %.7: type = ptr_type %.4 [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/operators
+// CHECK:STDOUT:     import Core//prelude/types
+// CHECK:STDOUT:     import Core//prelude/operators/arithmetic
+// CHECK:STDOUT:     import Core//prelude/operators/as
+// CHECK:STDOUT:     import Core//prelude/operators/bitwise
+// CHECK:STDOUT:     import Core//prelude/operators/comparison
+// CHECK:STDOUT:     import Core//prelude/types/bool
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .HasF = %HasF.decl
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .G = %G.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %HasF.decl: type = interface_decl @HasF [template = constants.%HasF.type] {} {}
+// CHECK:STDOUT:   %C.decl: %C.type = class_decl @C [template = constants.%C.1] {
+// CHECK:STDOUT:     %T.patt: type = symbolic_binding_pattern T, 0
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %T.param: type = param T, runtime_param<invalid>
+// CHECK:STDOUT:     %T.loc8: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   impl_decl @impl [template] {
+// CHECK:STDOUT:     %T.patt: type = symbolic_binding_pattern T, 0
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %T.param: type = param T, runtime_param<invalid>
+// CHECK:STDOUT:     %T.loc10: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:     %C.ref: %C.type = name_ref C, file.%C.decl [template = constants.%C.1]
+// CHECK:STDOUT:     %T.ref: type = name_ref T, %T.loc10 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:     %C.loc10: type = class_type @C, @C(constants.%T) [symbolic = %C.1 (constants.%C.2)]
+// CHECK:STDOUT:     %HasF.ref: type = name_ref HasF, file.%HasF.decl [template = constants.%HasF.type]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %G.decl: %G.type = fn_decl @G [template = constants.%G] {
+// CHECK:STDOUT:     %x.patt: %C.3 = binding_pattern x
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %C.ref: %C.type = name_ref C, file.%C.decl [template = constants.%C.1]
+// CHECK:STDOUT:     %.loc14_12: %.4 = struct_literal ()
+// CHECK:STDOUT:     %.loc14_10: type = converted %.loc14_12, constants.%.4 [template = constants.%.4]
+// CHECK:STDOUT:     %C: type = class_type @C, @C(constants.%.4) [template = constants.%C.3]
+// CHECK:STDOUT:     %x.param: %C.3 = param x, runtime_param0
+// CHECK:STDOUT:     %x: %C.3 = bind_name x, %x.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @HasF {
+// CHECK:STDOUT:   %Self: %HasF.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:   %F.decl: %F.type.1 = fn_decl @F.1 [template = constants.%F.1] {} {}
+// CHECK:STDOUT:   %.loc5: %.2 = assoc_entity element0, %F.decl [template = constants.%.3]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   .F = %.loc5
+// CHECK:STDOUT:   witness = (%F.decl)
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic impl @impl(%T.loc10: type) {
+// CHECK:STDOUT:   %T.1: type = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:   %C.1: type = class_type @C, @C(%T.1) [symbolic = %C.1 (constants.%C.2)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %F.type: type = fn_type @F.2, @impl(%T.1) [symbolic = %F.type (constants.%F.type.2)]
+// CHECK:STDOUT:   %F: @impl.%F.type (%F.type.2) = struct_value () [symbolic = %F (constants.%F.2)]
+// CHECK:STDOUT:   %.1: <witness> = interface_witness (%F) [symbolic = %.1 (constants.%.6)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   impl: %C.loc10 as %HasF.ref {
+// CHECK:STDOUT:     %F.decl: @impl.%F.type (%F.type.2) = fn_decl @F.2 [symbolic = @impl.%F (constants.%F.2)] {} {}
+// CHECK:STDOUT:     %.loc10: <witness> = interface_witness (%F.decl) [symbolic = %.1 (constants.%.6)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .F = %F.decl
+// CHECK:STDOUT:     witness = %.loc10
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic class @C(%T.loc8: type) {
+// CHECK:STDOUT:   %T.1: type = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:
+// CHECK:STDOUT:   class {
+// CHECK:STDOUT:     %.loc8: <witness> = complete_type_witness %.4 [template = constants.%.5]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .Self = constants.%C.2
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F.1(@HasF.%Self: %HasF.type) {
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn();
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F.2(@impl.%T.loc10: type) {
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn() {
+// CHECK:STDOUT:   !entry:
+// CHECK:STDOUT:     return
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @G(%x: %C.3) {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %x.ref: %C.3 = name_ref x, %x
+// CHECK:STDOUT:   %HasF.ref: type = name_ref HasF, file.%HasF.decl [template = constants.%HasF.type]
+// CHECK:STDOUT:   %F.ref: %.2 = name_ref F, @HasF.%.loc5 [template = constants.%.3]
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%Self) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @C(constants.%T) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @C(@impl.%T.1) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl(constants.%T) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT:   %C.1 => constants.%C.2
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %F.type => constants.%F.type.2
+// CHECK:STDOUT:   %F => constants.%F.2
+// CHECK:STDOUT:   %.1 => constants.%.6
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.2(constants.%T) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%C.2) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl(@impl.%T.1) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT:   %C.1 => constants.%C.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @C(constants.%.4) {
+// CHECK:STDOUT:   %T.1 => constants.%.4
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_todo_deduced_interface_argument.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T, 0 [symbolic]
+// CHECK:STDOUT:   %HasF.type.1: type = generic_interface_type @HasF [template]
+// CHECK:STDOUT:   %.1: type = tuple_type () [template]
+// CHECK:STDOUT:   %HasF: %HasF.type.1 = struct_value () [template]
+// CHECK:STDOUT:   %HasF.type.2: type = interface_type @HasF, @HasF(%T) [symbolic]
+// CHECK:STDOUT:   %Self: %HasF.type.2 = bind_symbolic_name Self, 1 [symbolic]
+// CHECK:STDOUT:   %F.type.1: type = fn_type @F.1, @HasF(%T) [symbolic]
+// CHECK:STDOUT:   %F.1: %F.type.1 = struct_value () [symbolic]
+// CHECK:STDOUT:   %.2: type = assoc_entity_type %HasF.type.2, %F.type.1 [symbolic]
+// CHECK:STDOUT:   %.3: %.2 = assoc_entity element0, @HasF.%F.decl [symbolic]
+// CHECK:STDOUT:   %.4: type = struct_type {} [template]
+// CHECK:STDOUT:   %F.type.2: type = fn_type @F.2, @impl(%T) [symbolic]
+// CHECK:STDOUT:   %F.2: %F.type.2 = struct_value () [symbolic]
+// CHECK:STDOUT:   %.5: <witness> = interface_witness (%F.2) [symbolic]
+// CHECK:STDOUT:   %G.type: type = fn_type @G [template]
+// CHECK:STDOUT:   %G: %G.type = struct_value () [template]
+// CHECK:STDOUT:   %HasF.type.3: type = interface_type @HasF, @HasF(%.4) [template]
+// CHECK:STDOUT:   %F.type.3: type = fn_type @F.1, @HasF(%.4) [template]
+// CHECK:STDOUT:   %F.3: %F.type.3 = struct_value () [template]
+// CHECK:STDOUT:   %.6: type = assoc_entity_type %HasF.type.3, %F.type.3 [template]
+// CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, @HasF.%F.decl [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/operators
+// CHECK:STDOUT:     import Core//prelude/types
+// CHECK:STDOUT:     import Core//prelude/operators/arithmetic
+// CHECK:STDOUT:     import Core//prelude/operators/as
+// CHECK:STDOUT:     import Core//prelude/operators/bitwise
+// CHECK:STDOUT:     import Core//prelude/operators/comparison
+// CHECK:STDOUT:     import Core//prelude/types/bool
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .HasF = %HasF.decl
+// CHECK:STDOUT:     .G = %G.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %HasF.decl: %HasF.type.1 = interface_decl @HasF [template = constants.%HasF] {
+// CHECK:STDOUT:     %T.patt: type = symbolic_binding_pattern T, 0
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %T.param: type = param T, runtime_param<invalid>
+// CHECK:STDOUT:     %T.loc4: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   impl_decl @impl [template] {
+// CHECK:STDOUT:     %T.patt: type = symbolic_binding_pattern T, 0
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %T.param: type = param T, runtime_param<invalid>
+// CHECK:STDOUT:     %T.loc8: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:     %.loc8_25.1: %.4 = struct_literal ()
+// CHECK:STDOUT:     %.loc8_25.2: type = converted %.loc8_25.1, constants.%.4 [template = constants.%.4]
+// CHECK:STDOUT:     %HasF.ref: %HasF.type.1 = name_ref HasF, file.%HasF.decl [template = constants.%HasF]
+// CHECK:STDOUT:     %T.ref: type = name_ref T, %T.loc8 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:     %HasF.type.loc8: type = interface_type @HasF, @HasF(constants.%T) [symbolic = %HasF.type.1 (constants.%HasF.type.2)]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %G.decl: %G.type = fn_decl @G [template = constants.%G] {
+// CHECK:STDOUT:     %x.patt: %.4 = binding_pattern x
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %.loc12_10.1: %.4 = struct_literal ()
+// CHECK:STDOUT:     %.loc12_10.2: type = converted %.loc12_10.1, constants.%.4 [template = constants.%.4]
+// CHECK:STDOUT:     %x.param: %.4 = param x, runtime_param0
+// CHECK:STDOUT:     %x: %.4 = bind_name x, %x.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic interface @HasF(%T.loc4: type) {
+// CHECK:STDOUT:   %T.1: type = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %HasF.type: type = interface_type @HasF, @HasF(%T.1) [symbolic = %HasF.type (constants.%HasF.type.2)]
+// CHECK:STDOUT:   %Self.2: %HasF.type.2 = bind_symbolic_name Self, 1 [symbolic = %Self.2 (constants.%Self)]
+// CHECK:STDOUT:   %F.type: type = fn_type @F.1, @HasF(%T.1) [symbolic = %F.type (constants.%F.type.1)]
+// CHECK:STDOUT:   %F: @HasF.%F.type (%F.type.1) = struct_value () [symbolic = %F (constants.%F.1)]
+// CHECK:STDOUT:   %.1: type = assoc_entity_type @HasF.%HasF.type (%HasF.type.2), @HasF.%F.type (%F.type.1) [symbolic = %.1 (constants.%.2)]
+// CHECK:STDOUT:   %.2: @HasF.%.1 (%.2) = assoc_entity element0, %F.decl [symbolic = %.2 (constants.%.3)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   interface {
+// CHECK:STDOUT:     %Self.1: @HasF.%HasF.type (%HasF.type.2) = bind_symbolic_name Self, 1 [symbolic = %Self.2 (constants.%Self)]
+// CHECK:STDOUT:     %F.decl: @HasF.%F.type (%F.type.1) = fn_decl @F.1 [symbolic = @HasF.%F (constants.%F.1)] {} {}
+// CHECK:STDOUT:     %.loc5: @HasF.%.1 (%.2) = assoc_entity element0, %F.decl [symbolic = %.2 (constants.%.3)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .Self = %Self.1
+// CHECK:STDOUT:     .F = %.loc5
+// CHECK:STDOUT:     witness = (%F.decl)
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic impl @impl(%T.loc8: type) {
+// CHECK:STDOUT:   %T.1: type = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:   %HasF.type.1: type = interface_type @HasF, @HasF(%T.1) [symbolic = %HasF.type.1 (constants.%HasF.type.2)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %F.type: type = fn_type @F.2, @impl(%T.1) [symbolic = %F.type (constants.%F.type.2)]
+// CHECK:STDOUT:   %F: @impl.%F.type (%F.type.2) = struct_value () [symbolic = %F (constants.%F.2)]
+// CHECK:STDOUT:   %.1: <witness> = interface_witness (%F) [symbolic = %.1 (constants.%.5)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   impl: %.loc8_25.2 as %HasF.type.loc8 {
+// CHECK:STDOUT:     %F.decl: @impl.%F.type (%F.type.2) = fn_decl @F.2 [symbolic = @impl.%F (constants.%F.2)] {} {}
+// CHECK:STDOUT:     %.loc8_38: <witness> = interface_witness (%F.decl) [symbolic = %.1 (constants.%.5)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .F = %F.decl
+// CHECK:STDOUT:     witness = %.loc8_38
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F.1(@HasF.%T.loc4: type, @HasF.%Self.1: @HasF.%HasF.type (%HasF.type.2)) {
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn();
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F.2(@impl.%T.loc8: type) {
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn() {
+// CHECK:STDOUT:   !entry:
+// CHECK:STDOUT:     return
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @G(%x: %.4) {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %x.ref: %.4 = name_ref x, %x
+// CHECK:STDOUT:   %HasF.ref: %HasF.type.1 = name_ref HasF, file.%HasF.decl [template = constants.%HasF]
+// CHECK:STDOUT:   %.loc18_12: %.4 = struct_literal ()
+// CHECK:STDOUT:   %.loc18_10: type = converted %.loc18_12, constants.%.4 [template = constants.%.4]
+// CHECK:STDOUT:   %HasF.type: type = interface_type @HasF, @HasF(constants.%.4) [template = constants.%HasF.type.3]
+// CHECK:STDOUT:   %.loc18_14: %.6 = specific_constant @HasF.%.loc5, @HasF(constants.%.4) [template = constants.%.7]
+// CHECK:STDOUT:   %F.ref: %.6 = name_ref F, %.loc18_14 [template = constants.%.7]
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @HasF(constants.%T) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %HasF.type => constants.%HasF.type.2
+// CHECK:STDOUT:   %Self.2 => constants.%Self
+// CHECK:STDOUT:   %F.type => constants.%F.type.1
+// CHECK:STDOUT:   %F => constants.%F.1
+// CHECK:STDOUT:   %.1 => constants.%.2
+// CHECK:STDOUT:   %.2 => constants.%.3
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%T, constants.%Self) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @HasF(@HasF.%T.1) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @HasF(@impl.%T.1) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl(constants.%T) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT:   %HasF.type.1 => constants.%HasF.type.2
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %F.type => constants.%F.type.2
+// CHECK:STDOUT:   %F => constants.%F.2
+// CHECK:STDOUT:   %.1 => constants.%.5
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.2(constants.%T) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%T, constants.%.4) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl(@impl.%T.1) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT:   %HasF.type.1 => constants.%HasF.type.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @HasF(constants.%.4) {
+// CHECK:STDOUT:   %T.1 => constants.%.4
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %HasF.type => constants.%HasF.type.3
+// CHECK:STDOUT:   %Self.2 => constants.%Self
+// CHECK:STDOUT:   %F.type => constants.%F.type.3
+// CHECK:STDOUT:   %F => constants.%F.3
+// CHECK:STDOUT:   %.1 => constants.%.6
+// CHECK:STDOUT:   %.2 => constants.%.7
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_incomplete_deduction.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %HasF.type: type = interface_type @HasF [template]
+// CHECK:STDOUT:   %Self: %HasF.type = bind_symbolic_name Self, 0 [symbolic]
+// CHECK:STDOUT:   %F.type.1: type = fn_type @F.1 [template]
+// CHECK:STDOUT:   %.1: type = tuple_type () [template]
+// CHECK:STDOUT:   %F.1: %F.type.1 = struct_value () [template]
+// CHECK:STDOUT:   %.2: type = assoc_entity_type %HasF.type, %F.type.1 [template]
+// CHECK:STDOUT:   %.3: %.2 = assoc_entity element0, @HasF.%F.decl [template]
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T, 0 [symbolic]
+// CHECK:STDOUT:   %U: type = bind_symbolic_name U, 1 [symbolic]
+// CHECK:STDOUT:   %F.type.2: type = fn_type @F.2, @impl(%T, %U) [symbolic]
+// CHECK:STDOUT:   %F.2: %F.type.2 = struct_value () [symbolic]
+// CHECK:STDOUT:   %.4: <witness> = interface_witness (%F.2) [symbolic]
+// CHECK:STDOUT:   %.5: type = struct_type {} [template]
+// CHECK:STDOUT:   %G.type: type = fn_type @G [template]
+// CHECK:STDOUT:   %G: %G.type = struct_value () [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/operators
+// CHECK:STDOUT:     import Core//prelude/types
+// CHECK:STDOUT:     import Core//prelude/operators/arithmetic
+// CHECK:STDOUT:     import Core//prelude/operators/as
+// CHECK:STDOUT:     import Core//prelude/operators/bitwise
+// CHECK:STDOUT:     import Core//prelude/operators/comparison
+// CHECK:STDOUT:     import Core//prelude/types/bool
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .HasF = %HasF.decl
+// CHECK:STDOUT:     .G = %G.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %HasF.decl: type = interface_decl @HasF [template = constants.%HasF.type] {} {}
+// CHECK:STDOUT:   impl_decl @impl [template] {
+// CHECK:STDOUT:     %T.patt: type = symbolic_binding_pattern T, 0
+// CHECK:STDOUT:     %U.patt: type = symbolic_binding_pattern U, 1
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %T.param: type = param T, runtime_param<invalid>
+// CHECK:STDOUT:     %T.loc9: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:     %U.param: type = param U, runtime_param<invalid>
+// CHECK:STDOUT:     %U.loc9: type = bind_symbolic_name U, 1, %U.param [symbolic = %U.1 (constants.%U)]
+// CHECK:STDOUT:     %T.ref: type = name_ref T, %T.loc9 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:     %HasF.ref: type = name_ref HasF, file.%HasF.decl [template = constants.%HasF.type]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %G.decl: %G.type = fn_decl @G [template = constants.%G] {
+// CHECK:STDOUT:     %x.patt: %.5 = binding_pattern x
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %.loc13_10.1: %.5 = struct_literal ()
+// CHECK:STDOUT:     %.loc13_10.2: type = converted %.loc13_10.1, constants.%.5 [template = constants.%.5]
+// CHECK:STDOUT:     %x.param: %.5 = param x, runtime_param0
+// CHECK:STDOUT:     %x: %.5 = bind_name x, %x.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @HasF {
+// CHECK:STDOUT:   %Self: %HasF.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:   %F.decl: %F.type.1 = fn_decl @F.1 [template = constants.%F.1] {} {}
+// CHECK:STDOUT:   %.loc5: %.2 = assoc_entity element0, %F.decl [template = constants.%.3]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   .F = %.loc5
+// CHECK:STDOUT:   witness = (%F.decl)
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic impl @impl(%T.loc9: type, %U.loc9: type) {
+// CHECK:STDOUT:   %T.1: type = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:   %U.1: type = bind_symbolic_name U, 1 [symbolic = %U.1 (constants.%U)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %F.type: type = fn_type @F.2, @impl(%T.1, %U.1) [symbolic = %F.type (constants.%F.type.2)]
+// CHECK:STDOUT:   %F: @impl.%F.type (%F.type.2) = struct_value () [symbolic = %F (constants.%F.2)]
+// CHECK:STDOUT:   %.1: <witness> = interface_witness (%F) [symbolic = %.1 (constants.%.4)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   impl: %T.ref as %HasF.ref {
+// CHECK:STDOUT:     %F.decl: @impl.%F.type (%F.type.2) = fn_decl @F.2 [symbolic = @impl.%F (constants.%F.2)] {} {}
+// CHECK:STDOUT:     %.loc9: <witness> = interface_witness (%F.decl) [symbolic = %.1 (constants.%.4)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .F = %F.decl
+// CHECK:STDOUT:     witness = %.loc9
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F.1(@HasF.%Self: %HasF.type) {
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn();
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F.2(@impl.%T.loc9: type, @impl.%U.loc9: type) {
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn() {
+// CHECK:STDOUT:   !entry:
+// CHECK:STDOUT:     return
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @G(%x: %.5) {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %x.ref: %.5 = name_ref x, %x
+// CHECK:STDOUT:   %HasF.ref: type = name_ref HasF, file.%HasF.decl [template = constants.%HasF.type]
+// CHECK:STDOUT:   %F.ref: %.2 = name_ref F, @HasF.%.loc5 [template = constants.%.3]
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%Self) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl(constants.%T, constants.%U) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT:   %U.1 => constants.%U
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %F.type => constants.%F.type.2
+// CHECK:STDOUT:   %F => constants.%F.2
+// CHECK:STDOUT:   %.1 => constants.%.4
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.2(constants.%T, constants.%U) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%T) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl(@impl.%T.1, @impl.%U.1) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT:   %U.1 => constants.%U
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_inconsistent_deduction.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T, 0 [symbolic]
+// CHECK:STDOUT:   %HasF.type.1: type = generic_interface_type @HasF [template]
+// CHECK:STDOUT:   %.1: type = tuple_type () [template]
+// CHECK:STDOUT:   %HasF: %HasF.type.1 = struct_value () [template]
+// CHECK:STDOUT:   %HasF.type.2: type = interface_type @HasF, @HasF(%T) [symbolic]
+// CHECK:STDOUT:   %Self: %HasF.type.2 = bind_symbolic_name Self, 1 [symbolic]
+// CHECK:STDOUT:   %F.type.1: type = fn_type @F.1, @HasF(%T) [symbolic]
+// CHECK:STDOUT:   %F.1: %F.type.1 = struct_value () [symbolic]
+// CHECK:STDOUT:   %.2: type = assoc_entity_type %HasF.type.2, %F.type.1 [symbolic]
+// CHECK:STDOUT:   %.3: %.2 = assoc_entity element0, @HasF.%F.decl [symbolic]
+// CHECK:STDOUT:   %F.type.2: type = fn_type @F.2, @impl(%T) [symbolic]
+// CHECK:STDOUT:   %F.2: %F.type.2 = struct_value () [symbolic]
+// CHECK:STDOUT:   %.4: <witness> = interface_witness (%F.2) [symbolic]
+// CHECK:STDOUT:   %A: type = class_type @A [template]
+// CHECK:STDOUT:   %.5: type = struct_type {} [template]
+// CHECK:STDOUT:   %.6: <witness> = complete_type_witness %.5 [template]
+// CHECK:STDOUT:   %B: type = class_type @B [template]
+// CHECK:STDOUT:   %G.type: type = fn_type @G [template]
+// CHECK:STDOUT:   %G: %G.type = struct_value () [template]
+// CHECK:STDOUT:   %.7: type = ptr_type %.5 [template]
+// CHECK:STDOUT:   %HasF.type.3: type = interface_type @HasF, @HasF(%B) [template]
+// CHECK:STDOUT:   %F.type.3: type = fn_type @F.1, @HasF(%B) [template]
+// CHECK:STDOUT:   %F.3: %F.type.3 = struct_value () [template]
+// CHECK:STDOUT:   %.8: type = assoc_entity_type %HasF.type.3, %F.type.3 [template]
+// CHECK:STDOUT:   %.9: %.8 = assoc_entity element0, @HasF.%F.decl [template]
+// CHECK:STDOUT:   %HasF.type.4: type = interface_type @HasF, @HasF(%A) [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/operators
+// CHECK:STDOUT:     import Core//prelude/types
+// CHECK:STDOUT:     import Core//prelude/operators/arithmetic
+// CHECK:STDOUT:     import Core//prelude/operators/as
+// CHECK:STDOUT:     import Core//prelude/operators/bitwise
+// CHECK:STDOUT:     import Core//prelude/operators/comparison
+// CHECK:STDOUT:     import Core//prelude/types/bool
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .HasF = %HasF.decl
+// CHECK:STDOUT:     .A = %A.decl
+// CHECK:STDOUT:     .B = %B.decl
+// CHECK:STDOUT:     .G = %G.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %HasF.decl: %HasF.type.1 = interface_decl @HasF [template = constants.%HasF] {
+// CHECK:STDOUT:     %T.patt: type = symbolic_binding_pattern T, 0
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %T.param: type = param T, runtime_param<invalid>
+// CHECK:STDOUT:     %T.loc4: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   impl_decl @impl [template] {
+// CHECK:STDOUT:     %T.patt: type = symbolic_binding_pattern T, 0
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %T.param: type = param T, runtime_param<invalid>
+// CHECK:STDOUT:     %T.loc8: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:     %T.ref.loc8_24: type = name_ref T, %T.loc8 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:     %HasF.ref: %HasF.type.1 = name_ref HasF, file.%HasF.decl [template = constants.%HasF]
+// CHECK:STDOUT:     %T.ref.loc8_34: type = name_ref T, %T.loc8 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:     %HasF.type.loc8: type = interface_type @HasF, @HasF(constants.%T) [symbolic = %HasF.type.1 (constants.%HasF.type.2)]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %A.decl: type = class_decl @A [template = constants.%A] {} {}
+// CHECK:STDOUT:   %B.decl: type = class_decl @B [template = constants.%B] {} {}
+// CHECK:STDOUT:   %G.decl: %G.type = fn_decl @G [template = constants.%G] {
+// CHECK:STDOUT:     %x.patt: %A = binding_pattern x
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %A.ref: type = name_ref A, file.%A.decl [template = constants.%A]
+// CHECK:STDOUT:     %x.param: %A = param x, runtime_param0
+// CHECK:STDOUT:     %x: %A = bind_name x, %x.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic interface @HasF(%T.loc4: type) {
+// CHECK:STDOUT:   %T.1: type = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %HasF.type: type = interface_type @HasF, @HasF(%T.1) [symbolic = %HasF.type (constants.%HasF.type.2)]
+// CHECK:STDOUT:   %Self.2: %HasF.type.2 = bind_symbolic_name Self, 1 [symbolic = %Self.2 (constants.%Self)]
+// CHECK:STDOUT:   %F.type: type = fn_type @F.1, @HasF(%T.1) [symbolic = %F.type (constants.%F.type.1)]
+// CHECK:STDOUT:   %F: @HasF.%F.type (%F.type.1) = struct_value () [symbolic = %F (constants.%F.1)]
+// CHECK:STDOUT:   %.1: type = assoc_entity_type @HasF.%HasF.type (%HasF.type.2), @HasF.%F.type (%F.type.1) [symbolic = %.1 (constants.%.2)]
+// CHECK:STDOUT:   %.2: @HasF.%.1 (%.2) = assoc_entity element0, %F.decl [symbolic = %.2 (constants.%.3)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   interface {
+// CHECK:STDOUT:     %Self.1: @HasF.%HasF.type (%HasF.type.2) = bind_symbolic_name Self, 1 [symbolic = %Self.2 (constants.%Self)]
+// CHECK:STDOUT:     %F.decl: @HasF.%F.type (%F.type.1) = fn_decl @F.1 [symbolic = @HasF.%F (constants.%F.1)] {} {}
+// CHECK:STDOUT:     %.loc5: @HasF.%.1 (%.2) = assoc_entity element0, %F.decl [symbolic = %.2 (constants.%.3)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .Self = %Self.1
+// CHECK:STDOUT:     .F = %.loc5
+// CHECK:STDOUT:     witness = (%F.decl)
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic impl @impl(%T.loc8: type) {
+// CHECK:STDOUT:   %T.1: type = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:   %HasF.type.1: type = interface_type @HasF, @HasF(%T.1) [symbolic = %HasF.type.1 (constants.%HasF.type.2)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %F.type: type = fn_type @F.2, @impl(%T.1) [symbolic = %F.type (constants.%F.type.2)]
+// CHECK:STDOUT:   %F: @impl.%F.type (%F.type.2) = struct_value () [symbolic = %F (constants.%F.2)]
+// CHECK:STDOUT:   %.1: <witness> = interface_witness (%F) [symbolic = %.1 (constants.%.4)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   impl: %T.ref.loc8_24 as %HasF.type.loc8 {
+// CHECK:STDOUT:     %F.decl: @impl.%F.type (%F.type.2) = fn_decl @F.2 [symbolic = @impl.%F (constants.%F.2)] {} {}
+// CHECK:STDOUT:     %.loc8: <witness> = interface_witness (%F.decl) [symbolic = %.1 (constants.%.4)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .F = %F.decl
+// CHECK:STDOUT:     witness = %.loc8
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @A {
+// CHECK:STDOUT:   %.loc12: <witness> = complete_type_witness %.5 [template = constants.%.6]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%A
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @B {
+// CHECK:STDOUT:   %.loc13: <witness> = complete_type_witness %.5 [template = constants.%.6]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%B
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F.1(@HasF.%T.loc4: type, @HasF.%Self.1: @HasF.%HasF.type (%HasF.type.2)) {
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn();
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F.2(@impl.%T.loc8: type) {
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn() {
+// CHECK:STDOUT:   !entry:
+// CHECK:STDOUT:     return
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @G(%x: %A) {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %x.ref: %A = name_ref x, %x
+// CHECK:STDOUT:   %HasF.ref: %HasF.type.1 = name_ref HasF, file.%HasF.decl [template = constants.%HasF]
+// CHECK:STDOUT:   %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
+// CHECK:STDOUT:   %HasF.type: type = interface_type @HasF, @HasF(constants.%B) [template = constants.%HasF.type.3]
+// CHECK:STDOUT:   %.loc21: %.8 = specific_constant @HasF.%.loc5, @HasF(constants.%B) [template = constants.%.9]
+// CHECK:STDOUT:   %F.ref: %.8 = name_ref F, %.loc21 [template = constants.%.9]
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @HasF(constants.%T) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %HasF.type => constants.%HasF.type.2
+// CHECK:STDOUT:   %Self.2 => constants.%Self
+// CHECK:STDOUT:   %F.type => constants.%F.type.1
+// CHECK:STDOUT:   %F => constants.%F.1
+// CHECK:STDOUT:   %.1 => constants.%.2
+// CHECK:STDOUT:   %.2 => constants.%.3
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%T, constants.%Self) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @HasF(@HasF.%T.1) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @HasF(@impl.%T.1) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl(constants.%T) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT:   %HasF.type.1 => constants.%HasF.type.2
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %F.type => constants.%F.type.2
+// CHECK:STDOUT:   %F => constants.%F.2
+// CHECK:STDOUT:   %.1 => constants.%.4
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.2(constants.%T) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%T, constants.%T) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl(@impl.%T.1) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT:   %HasF.type.1 => constants.%HasF.type.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @HasF(constants.%B) {
+// CHECK:STDOUT:   %T.1 => constants.%B
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %HasF.type => constants.%HasF.type.3
+// CHECK:STDOUT:   %Self.2 => constants.%Self
+// CHECK:STDOUT:   %F.type => constants.%F.type.3
+// CHECK:STDOUT:   %F => constants.%F.3
+// CHECK:STDOUT:   %.1 => constants.%.8
+// CHECK:STDOUT:   %.2 => constants.%.9
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl(constants.%A) {
+// CHECK:STDOUT:   %T.1 => constants.%A
+// CHECK:STDOUT:   %HasF.type.1 => constants.%HasF.type.4
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @HasF(constants.%A) {
+// CHECK:STDOUT:   %T.1 => constants.%A
+// CHECK:STDOUT: }
+// CHECK:STDOUT:

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

@@ -62,13 +62,13 @@ fn TestSpecific(a: A({})) -> {} {
 // CHECK:STDOUT:   %V: type = bind_symbolic_name V, 0 [symbolic]
 // CHECK:STDOUT:   %A.3: type = class_type @A, @A(%V) [symbolic]
 // CHECK:STDOUT:   %I.type.3: type = interface_type @I, @I(%V) [symbolic]
-// CHECK:STDOUT:   %F.type.2: type = fn_type @F.2 [template]
-// CHECK:STDOUT:   %F.2: %F.type.2 = struct_value () [template]
+// CHECK:STDOUT:   %F.type.2: type = fn_type @F.2, @impl(%V) [symbolic]
+// CHECK:STDOUT:   %F.2: %F.type.2 = struct_value () [symbolic]
 // CHECK:STDOUT:   %F.type.3: type = fn_type @F.1, @I(%V) [symbolic]
 // CHECK:STDOUT:   %F.3: %F.type.3 = struct_value () [symbolic]
 // CHECK:STDOUT:   %.7: type = assoc_entity_type %I.type.3, %F.type.3 [symbolic]
 // CHECK:STDOUT:   %.8: %.7 = assoc_entity element0, @I.%F.decl [symbolic]
-// CHECK:STDOUT:   %.9: <witness> = interface_witness (%F.2) [template]
+// CHECK:STDOUT:   %.9: <witness> = interface_witness (%F.2) [symbolic]
 // CHECK:STDOUT:   %.10: type = unbound_element_type %A.3, %V [symbolic]
 // CHECK:STDOUT:   %.11: type = struct_type {.n: %V} [symbolic]
 // CHECK:STDOUT:   %.12: <witness> = complete_type_witness %.11 [symbolic]
@@ -201,8 +201,13 @@ fn TestSpecific(a: A({})) -> {} {
 // CHECK:STDOUT:   %A.1: type = class_type @A, @A(%V.1) [symbolic = %A.1 (constants.%A.3)]
 // CHECK:STDOUT:   %I.type.1: type = interface_type @I, @I(%V.1) [symbolic = %I.type.1 (constants.%I.type.3)]
 // CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %F.type: type = fn_type @F.2, @impl(%V.1) [symbolic = %F.type (constants.%F.type.2)]
+// CHECK:STDOUT:   %F: @impl.%F.type (%F.type.2) = struct_value () [symbolic = %F (constants.%F.2)]
+// CHECK:STDOUT:   %.1: <witness> = interface_witness (%F) [symbolic = %.1 (constants.%.9)]
+// CHECK:STDOUT:
 // CHECK:STDOUT:   impl: %A.loc10 as %I.type.loc10 {
-// CHECK:STDOUT:     %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {
+// CHECK:STDOUT:     %F.decl: @impl.%F.type (%F.type.2) = fn_decl @F.2 [symbolic = @impl.%F (constants.%F.2)] {
 // CHECK:STDOUT:       %self.patt: @F.2.%A (%A.3) = binding_pattern self
 // CHECK:STDOUT:     } {
 // CHECK:STDOUT:       %Self.ref: type = name_ref Self, @impl.%A.loc10 [symbolic = %A (constants.%A.3)]
@@ -211,7 +216,7 @@ fn TestSpecific(a: A({})) -> {} {
 // CHECK:STDOUT:       %V.ref: type = name_ref V, @impl.%V.loc10 [symbolic = %V (constants.%V)]
 // CHECK:STDOUT:       %return: ref @F.2.%V (%V) = var <return slot>
 // CHECK:STDOUT:     }
-// CHECK:STDOUT:     %.loc10: <witness> = interface_witness (%F.decl) [template = constants.%.9]
+// CHECK:STDOUT:     %.loc10: <witness> = interface_witness (%F.decl) [symbolic = %.1 (constants.%.9)]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   !members:
 // CHECK:STDOUT:     .F = %F.decl
@@ -358,6 +363,11 @@ fn TestSpecific(a: A({})) -> {} {
 // CHECK:STDOUT:   %V.1 => constants.%V
 // CHECK:STDOUT:   %A.1 => constants.%A.3
 // CHECK:STDOUT:   %I.type.1 => constants.%I.type.3
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %F.type => constants.%F.type.2
+// CHECK:STDOUT:   %F => constants.%F.2
+// CHECK:STDOUT:   %.1 => constants.%.9
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @A(@F.2.%V) {
@@ -375,6 +385,12 @@ fn TestSpecific(a: A({})) -> {} {
 // CHECK:STDOUT:   %Self => constants.%A.3
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl(@impl.%V.1) {
+// CHECK:STDOUT:   %V.1 => constants.%V
+// CHECK:STDOUT:   %A.1 => constants.%A.3
+// CHECK:STDOUT:   %I.type.1 => constants.%I.type.3
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: specific @A(constants.%W) {
 // CHECK:STDOUT:   %T.1 => constants.%W
 // CHECK:STDOUT:

+ 10 - 0
toolchain/check/testdata/impl/no_prelude/generic_redeclaration.carbon

@@ -254,6 +254,8 @@ impl (C, C).0 as I {}
 // CHECK:STDOUT: generic impl @impl.5(%T.loc18: %I.type) {
 // CHECK:STDOUT:   %T.1: %I.type = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T.1)]
 // CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:
 // CHECK:STDOUT:   impl: %.loc18_21.2 as %Interface.ref {
 // CHECK:STDOUT:     %.loc18_36: <witness> = interface_witness () [template = constants.%.2]
 // CHECK:STDOUT:
@@ -265,6 +267,8 @@ impl (C, C).0 as I {}
 // CHECK:STDOUT: generic impl @impl.6(%T.loc19: %J.type) {
 // CHECK:STDOUT:   %T.1: %J.type = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T.2)]
 // CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:
 // CHECK:STDOUT:   impl: %.loc19_21.2 as %Interface.ref {
 // CHECK:STDOUT:     %.loc19_36: <witness> = interface_witness () [template = constants.%.2]
 // CHECK:STDOUT:
@@ -276,6 +280,8 @@ impl (C, C).0 as I {}
 // CHECK:STDOUT: generic impl @impl.7(%T.loc20: %K.type) {
 // CHECK:STDOUT:   %T.1: %K.type = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T.3)]
 // CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:
 // CHECK:STDOUT:   impl: %.loc20_21.2 as %Interface.ref {
 // CHECK:STDOUT:     %.loc20_36: <witness> = interface_witness () [template = constants.%.2]
 // CHECK:STDOUT:
@@ -287,6 +293,8 @@ impl (C, C).0 as I {}
 // CHECK:STDOUT: generic impl @impl.8(%T.loc21: %L.type) {
 // CHECK:STDOUT:   %T.1: %L.type = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T.4)]
 // CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:
 // CHECK:STDOUT:   impl: %.loc21_21.2 as %Interface.ref {
 // CHECK:STDOUT:     %.loc21_36: <witness> = interface_witness () [template = constants.%.2]
 // CHECK:STDOUT:
@@ -389,6 +397,8 @@ impl (C, C).0 as I {}
 // CHECK:STDOUT: generic impl @impl(%T.loc7: %I.type) {
 // CHECK:STDOUT:   %T.1: %I.type = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T)]
 // CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:
 // CHECK:STDOUT:   impl: %.loc7_21.2 as %J.ref.loc7 {
 // CHECK:STDOUT:   !members:
 // CHECK:STDOUT:     witness = <unexpected>.inst+21.loc7_28

+ 8 - 0
toolchain/check/testdata/impl/no_prelude/import_generic.carbon

@@ -117,6 +117,8 @@ impl forall [T:! type] C as I(T*) {}
 // CHECK:STDOUT:   %.1: type = ptr_type @impl.2.%T.1 (%T) [symbolic = %.1 (constants.%.4)]
 // CHECK:STDOUT:   %I.type.1: type = interface_type @I, @I(%.1) [symbolic = %I.type.1 (constants.%I.type.3)]
 // CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:
 // CHECK:STDOUT:   impl: %C.ref as %I.type.loc8 {
 // CHECK:STDOUT:     %.loc8_35: <witness> = interface_witness () [template = constants.%.5]
 // CHECK:STDOUT:
@@ -232,6 +234,8 @@ impl forall [T:! type] C as I(T*) {}
 // CHECK:STDOUT:   %T.1: type = bind_symbolic_name T, 0 [symbolic = %T.1 (constants.%T)]
 // CHECK:STDOUT:   %I.type.1: type = interface_type @I, @I(%T.1) [symbolic = %I.type.1 (constants.%I.type.2)]
 // CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:
 // CHECK:STDOUT:   impl: imports.%import_ref.5 as imports.%import_ref.6 {
 // CHECK:STDOUT:     %.loc4: <witness> = interface_witness () [template = constants.%.5]
 // CHECK:STDOUT:
@@ -245,6 +249,8 @@ impl forall [T:! type] C as I(T*) {}
 // CHECK:STDOUT:   %.1: type = ptr_type @impl.2.%T (%T) [symbolic = %.1 (constants.%.4)]
 // CHECK:STDOUT:   %I.type: type = interface_type @I, @I(%.1) [symbolic = %I.type (constants.%I.type.3)]
 // CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:
 // CHECK:STDOUT:   impl: imports.%import_ref.7 as imports.%import_ref.8 {
 // CHECK:STDOUT:   !members:
 // CHECK:STDOUT:     witness = imports.%import_ref.9
@@ -364,6 +370,8 @@ impl forall [T:! type] C as I(T*) {}
 // CHECK:STDOUT:   %.1: type = ptr_type @impl.2.%T.1 (%T) [symbolic = %.1 (constants.%.4)]
 // CHECK:STDOUT:   %I.type.1: type = interface_type @I, @I(%.1) [symbolic = %I.type.1 (constants.%I.type.3)]
 // CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:
 // CHECK:STDOUT:   impl: imports.%import_ref.7 as imports.%import_ref.8 {
 // CHECK:STDOUT:   !members:
 // CHECK:STDOUT:     witness = imports.%import_ref.9