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

Basic support for declaring generic impls. (#4336)

Update impl handling to more closely match other kinds of declaration,
including support for declaring and defining gneeric `impl`s.

When of performing redeclaration lookup for impls by looking for the
self and constraint type, produce a list of impls rather than a single
impl because it's possible for there to be multiple impls with different
deduced parameters but the same self type and constraint. Following
#3763, only consider impls to be redeclarations if they're spelled the
same, not just if they have the same self and constraint types.

No support yet for impl selection to deduce the arguments of a generic
impl.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
Richard Smith 1 год назад
Родитель
Сommit
2f3ad26f0e

+ 91 - 15
toolchain/check/handle_impl.cpp

@@ -5,8 +5,10 @@
 #include "toolchain/check/context.h"
 #include "toolchain/check/convert.h"
 #include "toolchain/check/decl_name_stack.h"
+#include "toolchain/check/generic.h"
 #include "toolchain/check/handle.h"
 #include "toolchain/check/impl.h"
+#include "toolchain/check/merge.h"
 #include "toolchain/check/modifiers.h"
 #include "toolchain/parse/typed_nodes.h"
 #include "toolchain/sem_ir/ids.h"
@@ -31,11 +33,13 @@ auto HandleParseNode(Context& context, Parse::ImplIntroducerId node_id)
   // parameters.
   context.decl_name_stack().PushScopeAndStartName();
 
+  // This might be a generic impl.
+  StartGenericDecl(context);
+
   // Push a pattern block for the signature of the `forall` (if any).
   // TODO: Instead use a separate parse node kinds for `impl` and `impl forall`,
   // and only push a pattern block in `forall` case.
   context.pattern_block_stack().Push();
-
   return true;
 }
 
@@ -44,6 +48,7 @@ auto HandleParseNode(Context& context, Parse::ImplForallId node_id) -> bool {
       context.node_stack().Pop<Parse::NodeKind::ImplicitParamList>();
   context.node_stack()
       .PopAndDiscardSoloNodeId<Parse::NodeKind::ImplicitParamListStart>();
+  RequireGenericParams(context, params_id);
   context.node_stack().Push(node_id, params_id);
   return true;
 }
@@ -180,6 +185,56 @@ static auto ExtendImpl(Context& context, Parse::NodeId extend_node,
   parent_scope.extended_scopes.push_back(interface.scope_id);
 }
 
+// Pops the parameters of an `impl`, forming a `NameComponent` with no
+// associated name that describes them.
+static auto PopImplIntroducerAndParamsAsNameComponent(
+    Context& context, Parse::AnyImplDeclId end_of_decl_node_id)
+    -> NameComponent {
+  auto [implicit_params_loc_id, implicit_params_id] =
+      context.node_stack().PopWithNodeIdIf<Parse::NodeKind::ImplForall>();
+
+  Parse::NodeId first_param_node_id =
+      context.node_stack().PopForSoloNodeId<Parse::NodeKind::ImplIntroducer>();
+  Parse::NodeId last_param_node_id = end_of_decl_node_id;
+
+  return {
+      .name_loc_id = Parse::NodeId::Invalid,
+      .name_id = SemIR::NameId::Invalid,
+      .first_param_node_id = first_param_node_id,
+      .last_param_node_id = last_param_node_id,
+      .implicit_params_loc_id = implicit_params_loc_id,
+      .implicit_params_id =
+          implicit_params_id.value_or(SemIR::InstBlockId::Invalid),
+      .params_loc_id = Parse::NodeId::Invalid,
+      .params_id = SemIR::InstBlockId::Invalid,
+      .pattern_block_id = context.pattern_block_stack().Pop(),
+  };
+}
+
+static auto MergeImplRedecl(Context& context, SemIR::Impl& new_impl,
+                            SemIR::ImplId prev_impl_id) -> bool {
+  auto& prev_impl = context.impls().Get(prev_impl_id);
+
+  // TODO: Following #3763, disallow redeclarations in different scopes.
+
+  // If the parameters aren't the same, then this is not a redeclaration of this
+  // `impl`. Keep looking for a prior declaration without issuing a diagnostic.
+  if (!CheckRedeclParamsMatch(context, DeclParams(new_impl),
+                              DeclParams(prev_impl), SemIR::SpecificId::Invalid,
+                              /*check_syntax=*/true, /*diagnose=*/false)) {
+    // NOLINTNEXTLINE(readability-simplify-boolean-expr)
+    return false;
+  }
+
+  // TODO: CheckIsAllowedRedecl. We don't have a suitable NameId; decide if we
+  // need to treat the `T as I` as a kind of name.
+
+  // TODO: Merge information from the new declaration into the old one as
+  // needed.
+
+  return true;
+}
+
 // Build an ImplDecl describing the signature of an impl. This handles the
 // common logic shared by impl forward declarations and impl definitions.
 static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId node_id,
@@ -189,10 +244,9 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId node_id,
       context.node_stack().PopExprWithNodeId();
   auto [self_type_node, self_type_id] =
       context.node_stack().PopWithNodeId<Parse::NodeCategory::ImplAs>();
-  auto [params_node, params_id] =
-      context.node_stack().PopWithNodeIdIf<Parse::NodeKind::ImplForall>();
+  // Pop the `impl` introducer and any `forall` parameters as a "name".
+  auto name = PopImplIntroducerAndParamsAsNameComponent(context, node_id);
   auto decl_block_id = context.inst_block_stack().Pop();
-  context.node_stack().PopForSoloNodeId<Parse::NodeKind::ImplIntroducer>();
 
   // Convert the constraint expression to a type.
   // TODO: Check that its constant value is a constraint.
@@ -212,24 +266,46 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId node_id,
 
   // TODO: Check for an orphan `impl`.
 
-  // TODO: Check parameters. Store them on the `Impl` in some form.
-  static_cast<void>(params_id);
-
   // Add the impl declaration.
-  // TODO: Does lookup in an impl file need to look for a prior impl declaration
-  // in the api file?
-  auto impl_id = context.impls().LookupOrAdd(self_type_id, constraint_type_id);
-  context.impls().Get(impl_id).pattern_block_id =
-      context.pattern_block_stack().Pop();
-  SemIR::ImplDecl impl_decl = {.impl_id = impl_id,
+  SemIR::ImplDecl impl_decl = {.impl_id = SemIR::ImplId::Invalid,
                                .decl_block_id = decl_block_id};
-  auto impl_decl_id = context.AddInst(node_id, impl_decl);
+  auto impl_decl_id =
+      context.AddPlaceholderInst(SemIR::LocIdAndInst(node_id, impl_decl));
+
+  SemIR::Impl impl_info = {
+      name_context.MakeEntityWithParamsBase(name, impl_decl_id,
+                                            /*is_extern=*/false,
+                                            SemIR::LibraryNameId::Invalid),
+      {.self_id = self_type_id, .constraint_id = constraint_type_id}};
+
+  // Add the impl declaration.
+  auto& lookup_bucket = context.impls().GetOrAddLookupBucket(
+      impl_info.self_id, impl_info.constraint_id);
+  for (auto prev_impl_id : lookup_bucket) {
+    if (MergeImplRedecl(context, impl_info, prev_impl_id)) {
+      impl_decl.impl_id = prev_impl_id;
+      break;
+    }
+  }
+
+  // Create a new impl if this isn't a valid redeclaration.
+  if (!impl_decl.impl_id.is_valid()) {
+    impl_info.generic_id = FinishGenericDecl(context, impl_decl_id);
+    impl_decl.impl_id = context.impls().Add(impl_info);
+    lookup_bucket.push_back(impl_decl.impl_id);
+  } else {
+    FinishGenericRedecl(context, impl_decl_id,
+                        context.impls().Get(impl_decl.impl_id).generic_id);
+  }
+
+  // Write the impl ID into the ImplDecl.
+  context.ReplaceInstBeforeConstantUse(impl_decl_id, impl_decl);
 
   // For an `extend impl` declaration, mark the impl as extending this `impl`.
   if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extend)) {
     auto extend_node = introducer.modifier_node_id(ModifierOrder::Decl);
     ExtendImpl(context, extend_node, node_id, self_type_node, self_type_id,
-               params_node, constraint_type_id);
+               name.implicit_params_loc_id, constraint_type_id);
   }
 
   if (!is_definition && context.IsImplFile()) {

+ 169 - 38
toolchain/check/import_ref.cpp

@@ -560,10 +560,16 @@ class ImportRefResolver {
     if (!generic_id.is_valid()) {
       return SemIR::ConstantId::Invalid;
     }
-    return GetLocalConstantId(
-        import_ir_.insts()
-            .Get(import_ir_.generics().Get(generic_id).decl_id)
-            .type_id());
+    auto import_decl_inst_id = import_ir_.generics().Get(generic_id).decl_id;
+    auto import_decl_inst = import_ir_.insts().Get(import_decl_inst_id);
+    if (import_decl_inst.Is<SemIR::ImplDecl>()) {
+      // For an impl declaration, the imported entity can be found via the
+      // declaration.
+      return GetLocalConstantId(import_decl_inst_id);
+    }
+    // For all other kinds of declaration, the imported entity can be found via
+    // the type of the declaration.
+    return GetLocalConstantId(import_decl_inst.type_id());
   }
 
   // Gets a local generic ID given the corresponding local constant ID returned
@@ -572,9 +578,9 @@ class ImportRefResolver {
     if (!local_const_id.is_valid()) {
       return SemIR::GenericId::Invalid;
     }
-    auto type = context_.insts().Get(
+    auto inst = context_.insts().Get(
         context_.constant_values().GetInstId(local_const_id));
-    CARBON_KIND_SWITCH(type) {
+    CARBON_KIND_SWITCH(inst) {
       case CARBON_KIND(SemIR::FunctionType fn_type): {
         return context_.functions().Get(fn_type.function_id).generic_id;
       }
@@ -586,8 +592,11 @@ class ImportRefResolver {
             .Get(interface_type.interface_id)
             .generic_id;
       }
+      case CARBON_KIND(SemIR::ImplDecl impl_decl): {
+        return context_.impls().Get(impl_decl.impl_id).generic_id;
+      }
       default: {
-        CARBON_FATAL("Unexpected type for generic declaration: {0}", type);
+        CARBON_FATAL("Unexpected inst for generic declaration: {0}", inst);
       }
     }
   }
@@ -781,10 +790,6 @@ class ImportRefResolver {
     // Get the constant value for the scope.
     auto const_id = SemIR::ConstantId::Invalid;
     CARBON_KIND_SWITCH(*inst) {
-      case SemIR::ImplDecl::Kind:
-        // TODO: Import the scope for an `impl` definition.
-        return SemIR::NameScopeId::Invalid;
-
       case SemIR::Namespace::Kind:
         // If the namespace has already been imported, we can use its constant.
         // However, if it hasn't, we use Invalid instead of adding it to the
@@ -808,6 +813,9 @@ class ImportRefResolver {
       case CARBON_KIND(SemIR::ClassType inst): {
         return context_.classes().Get(inst.class_id).scope_id;
       }
+      case CARBON_KIND(SemIR::ImplDecl inst): {
+        return context_.impls().Get(inst.impl_id).scope_id;
+      }
       case CARBON_KIND(SemIR::InterfaceType inst): {
         return context_.interfaces().Get(inst.interface_id).scope_id;
       }
@@ -1037,6 +1045,9 @@ class ImportRefResolver {
       case CARBON_KIND(SemIR::GenericInterfaceType inst): {
         return TryResolveTypedInst(inst);
       }
+      case CARBON_KIND(SemIR::ImplDecl inst): {
+        return TryResolveTypedInst(inst, const_id);
+      }
       case CARBON_KIND(SemIR::ImportRefLoaded inst): {
         return TryResolveTypedInst(inst, inst_id);
       }
@@ -1569,6 +1580,138 @@ class ImportRefResolver {
         context_.types().GetConstantId(interface_val.type_id()));
   }
 
+  // Forms a constant ID that represents the given instruction ID that denotes
+  // an impl declaration. Impl declarations don't have a constant value, but for
+  // the purposes of importing we pretend that they do.
+  //
+  // TODO: Consider alternative options here. We could make impl declarations
+  // actually evaluate to themselves to avoid this hack.
+  static auto ImplDeclIdAsConstantId(SemIR::InstId impl_decl_id)
+      -> SemIR::ConstantId {
+    return SemIR::ConstantId::ForTemplateConstant(impl_decl_id);
+  }
+
+  // Gets the instruction ID for an impl declaration represented by the
+  // specified constant ID.
+  auto ConstantIdAsImplDeclId(SemIR::ConstantId impl_const_id)
+      -> SemIR::InstId {
+    return context_.constant_values().GetInstId(impl_const_id);
+  }
+
+  // Make a declaration of an impl. This is done as a separate step from
+  // importing the impl definition in order to resolve cycles.
+  auto MakeImplDeclaration(const SemIR::Impl& import_impl)
+      -> std::pair<SemIR::ImplId, SemIR::ConstantId> {
+    SemIR::ImplDecl impl_decl = {.impl_id = SemIR::ImplId::Invalid,
+                                 .decl_block_id = SemIR::InstBlockId::Empty};
+    auto impl_decl_id =
+        context_.AddPlaceholderInstInNoBlock(context_.MakeImportedLocAndInst(
+            AddImportIRInst(import_impl.latest_decl_id()), impl_decl));
+    impl_decl.impl_id = context_.impls().Add(
+        {GetIncompleteLocalEntityBase(impl_decl_id, import_impl),
+         {.self_id = SemIR::TypeId::Invalid,
+          .constraint_id = SemIR::TypeId::Invalid,
+          .witness_id = SemIR::InstId::Invalid}});
+
+    // Write the impl ID into the ImplDecl.
+    context_.ReplaceInstBeforeConstantUse(impl_decl_id, impl_decl);
+    return {impl_decl.impl_id, ImplDeclIdAsConstantId(impl_decl_id)};
+  }
+
+  // Imports the definition of an impl.
+  auto AddImplDefinition(const SemIR::Impl& import_impl, SemIR::Impl& new_impl,
+                         SemIR::InstId witness_id) -> void {
+    new_impl.definition_id = new_impl.first_owning_decl_id;
+
+    new_impl.witness_id = witness_id;
+
+    // Import the definition scope, if we might need it. Name lookup is never
+    // performed into this scope by a user of the impl, so this is only
+    // necessary in the same library that defined the impl, in order to support
+    // defining members of the impl out of line in the impl file when the impl
+    // is defined in the API file.
+    if (import_ir_id_ == SemIR::ImportIRId::ApiForImpl) {
+      new_impl.scope_id = context_.name_scopes().Add(
+          new_impl.first_owning_decl_id, SemIR::NameId::Invalid,
+          new_impl.parent_scope_id);
+      auto& new_scope = context_.name_scopes().Get(new_impl.scope_id);
+      const auto& import_scope =
+          import_ir_.name_scopes().Get(import_impl.scope_id);
+
+      // Push a block so that we can add scoped instructions to it.
+      context_.inst_block_stack().Push();
+      AddNameScopeImportRefs(import_scope, new_scope);
+      new_impl.body_block_id = context_.inst_block_stack().Pop();
+    }
+  }
+
+  auto TryResolveTypedInst(SemIR::ImplDecl inst,
+                           SemIR::ConstantId impl_const_id) -> ResolveResult {
+    // TODO: This duplicates a lot of the handling of interfaces, classes, and
+    // functions. Factor out the commonality.
+    const auto& import_impl = import_ir_.impls().Get(inst.impl_id);
+
+    SemIR::ImplId impl_id = SemIR::ImplId::Invalid;
+    if (!impl_const_id.is_valid()) {
+      if (HasNewWork()) {
+        // This is the end of the first phase. Don't make a new impl yet if we
+        // already have new work.
+        return Retry();
+      }
+
+      // On the second phase, create a forward declaration of the impl for any
+      // recursive references.
+      std::tie(impl_id, impl_const_id) = MakeImplDeclaration(import_impl);
+    } else {
+      // On the third phase, compute the impl ID from the "constant value" of
+      // the declaration, which is a reference to the created ImplDecl.
+      auto impl_const_inst = context_.insts().GetAs<SemIR::ImplDecl>(
+          context_.constant_values().GetInstId(impl_const_id));
+      impl_id = impl_const_inst.impl_id;
+    }
+
+    // Load constants for the definition.
+    auto parent_scope_id = GetLocalNameScopeId(import_impl.parent_scope_id);
+    auto implicit_param_const_ids =
+        GetLocalParamConstantIds(import_impl.implicit_param_refs_id);
+    auto generic_data = GetLocalGenericData(import_impl.generic_id);
+    auto self_const_id = GetLocalConstantId(import_impl.self_id);
+    auto constraint_const_id = GetLocalConstantId(import_impl.constraint_id);
+
+    if (HasNewWork()) {
+      return Retry(impl_const_id);
+    }
+
+    auto& new_impl = context_.impls().Get(impl_id);
+    new_impl.parent_scope_id = parent_scope_id;
+    new_impl.implicit_param_refs_id = GetLocalParamRefsId(
+        import_impl.implicit_param_refs_id, implicit_param_const_ids);
+    CARBON_CHECK(!import_impl.param_refs_id.is_valid() &&
+                 !new_impl.param_refs_id.is_valid());
+    SetGenericData(import_impl.generic_id, new_impl.generic_id, generic_data);
+    new_impl.self_id = context_.GetTypeIdForTypeConstant(self_const_id);
+    new_impl.constraint_id =
+        context_.GetTypeIdForTypeConstant(constraint_const_id);
+
+    if (import_impl.is_defined()) {
+      auto witness_id = AddImportRef(
+          context_, {.ir_id = import_ir_id_, .inst_id = import_impl.witness_id},
+          SemIR::EntityNameId::Invalid);
+      AddImplDefinition(import_impl, new_impl, witness_id);
+    }
+
+    // If the `impl` is declared in the API file corresponding to the current
+    // file, add this to impl lookup so that it can be found by redeclarations
+    // in the current file.
+    if (import_ir_id_ == SemIR::ImportIRId::ApiForImpl) {
+      context_.impls()
+          .GetOrAddLookupBucket(new_impl.self_id, new_impl.constraint_id)
+          .push_back(impl_id);
+    }
+
+    return ResolveAsConstant(impl_const_id);
+  }
+
   auto TryResolveTypedInst(SemIR::ImportRefLoaded /*inst*/,
                            SemIR::InstId inst_id) -> ResolveResult {
     // Return the constant for the instruction of the imported constant.
@@ -1883,9 +2026,18 @@ class ImportRefResolver {
     // Note that the individual Finish steps can add new pending work, so keep
     // going until we have no more work to do.
     while (!pending_generics_.empty() || !pending_specifics_.empty()) {
-      while (!pending_generics_.empty()) {
-        FinishPendingGeneric(pending_generics_.pop_back_val());
+      // Process generics in the order that we added them because a later
+      // generic might refer to an earlier one, and the calls to
+      // RebuildGenericEvalBlock assume that the reachable SemIR is in a valid
+      // state.
+      // TODO: Import the generic eval block rather than calling
+      // RebuildGenericEvalBlock to rebuild it so that order doesn't matter.
+      // NOLINTNEXTLINE(modernize-loop-convert)
+      for (size_t i = 0; i != pending_generics_.size(); ++i) {
+        FinishPendingGeneric(pending_generics_[i]);
       }
+      pending_generics_.clear();
+
       while (!pending_specifics_.empty()) {
         FinishPendingSpecific(pending_specifics_.pop_back_val());
       }
@@ -2076,30 +2228,6 @@ auto LoadImportRef(Context& context, SemIR::InstId inst_id) -> void {
   }
 }
 
-// Imports the impl `import_impl_id` from the imported IR `import_ir`.
-static auto ImportImpl(Context& context, SemIR::ImportIRId import_ir_id,
-                       const SemIR::File& import_ir,
-                       SemIR::ImplId import_impl_id) -> void {
-  // Resolve the imported impl to a local impl ID.
-  ImportRefResolver resolver(context, import_ir_id);
-  const auto& import_impl = import_ir.impls().Get(import_impl_id);
-  auto self_id = resolver.ResolveType(import_impl.self_id);
-  auto constraint_id = resolver.ResolveType(import_impl.constraint_id);
-
-  // Import the definition if the impl is defined.
-  // TODO: Do we need to check for multiple definitions?
-  auto impl_id = context.impls().LookupOrAdd(self_id, constraint_id);
-  if (import_impl.is_defined()) {
-    // TODO: Create a scope for the `impl` if necessary.
-    // TODO: Consider importing the definition_id.
-
-    auto& impl = context.impls().Get(impl_id);
-    impl.witness_id = AddImportRef(
-        context, {.ir_id = import_ir_id, .inst_id = import_impl.witness_id},
-        SemIR::EntityNameId::Invalid);
-  }
-}
-
 // TODO: This doesn't belong in this file. Consider moving the import resolver
 // and this file elsewhere.
 auto ImportImpls(Context& context) -> void {
@@ -2112,7 +2240,10 @@ auto ImportImpls(Context& context) -> void {
     SemIR::ImportIRId import_ir_id(import_index);
     for (auto impl_index : llvm::seq(import_ir.sem_ir->impls().size())) {
       SemIR::ImplId impl_id(impl_index);
-      ImportImpl(context, import_ir_id, *import_ir.sem_ir, impl_id);
+
+      // Resolve the imported impl to a local impl ID.
+      ImportRefResolver resolver(context, import_ir_id);
+      resolver.Resolve(import_ir.sem_ir->impls().Get(impl_id).first_decl_id());
     }
   }
 }

+ 29 - 19
toolchain/check/merge.cpp

@@ -192,16 +192,17 @@ static auto EntityHasParamError(Context& context, const DeclParams& info)
 
 // Returns false if a param differs for a redeclaration. The caller is expected
 // to provide a diagnostic.
-static auto CheckRedeclParam(Context& context,
-                             llvm::StringLiteral param_diag_label,
-                             int32_t param_index,
-                             SemIR::InstId new_param_ref_id,
-                             SemIR::InstId prev_param_ref_id,
-                             SemIR::SpecificId prev_specific_id) -> bool {
+static auto CheckRedeclParam(
+    Context& context, llvm::StringLiteral param_diag_label, int32_t param_index,
+    SemIR::InstId new_param_ref_id, SemIR::InstId prev_param_ref_id,
+    SemIR::SpecificId prev_specific_id, bool diagnose) -> bool {
   // TODO: Consider differentiating between type and name mistakes. For now,
   // taking the simpler approach because I also think we may want to refactor
   // params.
-  auto diagnose = [&]() {
+  auto emit_diagnostic = [&]() {
+    if (!diagnose) {
+      return;
+    }
     CARBON_DIAGNOSTIC(RedeclParamDiffers, Error,
                       "redeclaration differs at {0}parameter {1}",
                       llvm::StringLiteral, int32_t);
@@ -222,7 +223,7 @@ static auto CheckRedeclParam(Context& context,
           new_param_ref.type_id(),
           SemIR::GetTypeInSpecific(context.sem_ir(), prev_specific_id,
                                    prev_param_ref.type_id()))) {
-    diagnose();
+    emit_diagnostic();
     return false;
   }
 
@@ -232,7 +233,7 @@ static auto CheckRedeclParam(Context& context,
     prev_param_ref =
         context.insts().Get(prev_param_ref.As<SemIR::AddrPattern>().inner_id);
     if (new_param_ref.kind() != prev_param_ref.kind()) {
-      diagnose();
+      emit_diagnostic();
       return false;
     }
   }
@@ -247,7 +248,7 @@ static auto CheckRedeclParam(Context& context,
   auto new_param = new_param_ref.As<SemIR::Param>();
   auto prev_param = prev_param_ref.As<SemIR::Param>();
   if (new_param.name_id != prev_param.name_id) {
-    diagnose();
+    emit_diagnostic();
     return false;
   }
 
@@ -260,7 +261,8 @@ static auto CheckRedeclParams(Context& context, SemIRLoc new_decl_loc,
                               SemIRLoc prev_decl_loc,
                               SemIR::InstBlockId prev_param_refs_id,
                               llvm::StringLiteral param_diag_label,
-                              SemIR::SpecificId prev_specific_id) -> bool {
+                              SemIR::SpecificId prev_specific_id, bool diagnose)
+    -> bool {
   // This will often occur for empty params.
   if (new_param_refs_id == prev_param_refs_id) {
     return true;
@@ -268,6 +270,9 @@ static auto CheckRedeclParams(Context& context, SemIRLoc new_decl_loc,
 
   // If exactly one of the parameter lists was present, they differ.
   if (new_param_refs_id.is_valid() != prev_param_refs_id.is_valid()) {
+    if (!diagnose) {
+      return false;
+    }
     CARBON_DIAGNOSTIC(RedeclParamListDiffers, Error,
                       "redeclaration differs because of {1}{0}parameter list",
                       llvm::StringLiteral, llvm::StringLiteral);
@@ -288,6 +293,9 @@ static auto CheckRedeclParams(Context& context, SemIRLoc new_decl_loc,
   const auto new_param_ref_ids = context.inst_blocks().Get(new_param_refs_id);
   const auto prev_param_ref_ids = context.inst_blocks().Get(prev_param_refs_id);
   if (new_param_ref_ids.size() != prev_param_ref_ids.size()) {
+    if (!diagnose) {
+      return false;
+    }
     CARBON_DIAGNOSTIC(
         RedeclParamCountDiffers, Error,
         "redeclaration differs because of {0}parameter count of {1}",
@@ -306,7 +314,7 @@ static auto CheckRedeclParams(Context& context, SemIRLoc new_decl_loc,
   for (auto [index, new_param_ref_id, prev_param_ref_id] :
        llvm::enumerate(new_param_ref_ids, prev_param_ref_ids)) {
     if (!CheckRedeclParam(context, param_diag_label, index, new_param_ref_id,
-                          prev_param_ref_id, prev_specific_id)) {
+                          prev_param_ref_id, prev_specific_id, diagnose)) {
       return false;
     }
   }
@@ -338,8 +346,8 @@ static auto CheckRedeclParamSyntax(Context& context,
                                    Parse::NodeId new_first_param_node_id,
                                    Parse::NodeId new_last_param_node_id,
                                    Parse::NodeId prev_first_param_node_id,
-                                   Parse::NodeId prev_last_param_node_id)
-    -> bool {
+                                   Parse::NodeId prev_last_param_node_id,
+                                   bool diagnose) -> bool {
   // Parse nodes may not always be available to compare.
   // TODO: Support cross-file syntax checks. Right now imports provide invalid
   // nodes, and we'll need to follow the declaration to its original file to
@@ -366,6 +374,9 @@ static auto CheckRedeclParamSyntax(Context& context,
   // sizes here.
   for (auto [new_node_id, prev_node_id] : llvm::zip(new_range, prev_range)) {
     if (!IsNodeSyntaxEqual(context, new_node_id, prev_node_id)) {
+      if (!diagnose) {
+        return false;
+      }
       CARBON_DIAGNOSTIC(RedeclParamSyntaxDiffers, Error,
                         "redeclaration syntax differs here");
       CARBON_DIAGNOSTIC(RedeclParamSyntaxPrevious, Note,
@@ -374,7 +385,6 @@ static auto CheckRedeclParamSyntax(Context& context,
           .Build(new_node_id, RedeclParamSyntaxDiffers)
           .Note(prev_node_id, RedeclParamSyntaxPrevious)
           .Emit();
-
       return false;
     }
   }
@@ -385,7 +395,7 @@ static auto CheckRedeclParamSyntax(Context& context,
 auto CheckRedeclParamsMatch(Context& context, const DeclParams& new_entity,
                             const DeclParams& prev_entity,
                             SemIR::SpecificId prev_specific_id,
-                            bool check_syntax) -> bool {
+                            bool check_syntax, bool diagnose) -> bool {
   if (EntityHasParamError(context, new_entity) ||
       EntityHasParamError(context, prev_entity)) {
     return false;
@@ -393,19 +403,19 @@ auto CheckRedeclParamsMatch(Context& context, const DeclParams& new_entity,
   if (!CheckRedeclParams(context, new_entity.loc,
                          new_entity.implicit_param_refs_id, prev_entity.loc,
                          prev_entity.implicit_param_refs_id, "implicit ",
-                         prev_specific_id)) {
+                         prev_specific_id, diagnose)) {
     return false;
   }
   if (!CheckRedeclParams(context, new_entity.loc, new_entity.param_refs_id,
                          prev_entity.loc, prev_entity.param_refs_id, "",
-                         prev_specific_id)) {
+                         prev_specific_id, diagnose)) {
     return false;
   }
   if (check_syntax &&
       !CheckRedeclParamSyntax(context, new_entity.first_param_node_id,
                               new_entity.last_param_node_id,
                               prev_entity.first_param_node_id,
-                              prev_entity.last_param_node_id)) {
+                              prev_entity.last_param_node_id, diagnose)) {
     return false;
   }
   return true;

+ 3 - 3
toolchain/check/merge.h

@@ -93,13 +93,13 @@ struct DeclParams {
 };
 
 // Checks that the parameters in a redeclaration of an entity match the
-// parameters in the prior declaration. If not, produces a diagnostic and
-// returns false.
+// parameters in the prior declaration. If not, produces a diagnostic if
+// `diagnose` is true, and returns false.
 auto CheckRedeclParamsMatch(
     Context& context, const DeclParams& new_entity,
     const DeclParams& prev_entity,
     SemIR::SpecificId prev_specific_id = SemIR::SpecificId::Invalid,
-    bool check_syntax = true) -> bool;
+    bool check_syntax = true, bool diagnose = true) -> bool;
 
 }  // namespace Carbon::Check
 

+ 30 - 16
toolchain/check/testdata/impl/fail_extend_impl_forall.carbon

@@ -100,19 +100,24 @@ class C {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.2 {
-// CHECK:STDOUT:   %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {
-// CHECK:STDOUT:     %x.patt: @F.2.%T (%T) = binding_pattern x
-// CHECK:STDOUT:   } {
-// CHECK:STDOUT:     %T.ref: type = name_ref T, @impl.%T [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_56: <witness> = interface_witness (%F.decl) [template = constants.%.5]
+// CHECK:STDOUT: generic impl @impl(%T.loc19: type) {
+// CHECK:STDOUT:   %T.1: type = bind_symbolic_name T 0 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:   %.1: type = interface_type @GenericInterface, @GenericInterface(%T.1) [symbolic = %.1 (constants.%.2)]
 // CHECK:STDOUT:
-// CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .F = %F.decl
-// CHECK:STDOUT:   witness = %.loc19_56
+// CHECK:STDOUT:   impl: %C as %.2 {
+// CHECK:STDOUT:     %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {
+// CHECK:STDOUT:       %x.patt: @F.2.%T (%T) = binding_pattern x
+// CHECK:STDOUT:     } {
+// 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_56: <witness> = interface_witness (%F.decl) [template = constants.%.5]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .F = %F.decl
+// CHECK:STDOUT:     witness = %.loc19_56
+// CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
@@ -120,10 +125,10 @@ class C {
 // 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: type = bind_symbolic_name T 0, %T.param [symbolic = constants.%T]
+// CHECK:STDOUT:     %T.loc19: type = bind_symbolic_name T 0, %T.param [symbolic = %T.1 (constants.%T)]
 // CHECK:STDOUT:     %GenericInterface.ref: %GenericInterface.type = name_ref GenericInterface, file.%GenericInterface.decl [template = constants.%GenericInterface]
-// CHECK:STDOUT:     %T.ref: type = name_ref T, %T [symbolic = constants.%T]
-// CHECK:STDOUT:     %.loc19_52: type = interface_type @GenericInterface, @GenericInterface(constants.%T) [symbolic = constants.%.2]
+// CHECK:STDOUT:     %T.ref: type = name_ref T, %T.loc19 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:     %.loc19_52: type = interface_type @GenericInterface, @GenericInterface(constants.%T) [symbolic = %.1 (constants.%.2)]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc22: <witness> = complete_type_witness %.6 [template = constants.%.7]
 // CHECK:STDOUT:
@@ -138,7 +143,7 @@ class C {
 // CHECK:STDOUT:   fn(%x: @F.1.%T (%T));
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: generic fn @F.2(@impl.%T: type) {
+// CHECK:STDOUT: generic fn @F.2(@impl.%T.loc19: type) {
 // CHECK:STDOUT:   %T: type = bind_symbolic_name T 0 [symbolic = %T (constants.%T)]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !definition:
@@ -169,6 +174,15 @@ class C {
 // CHECK:STDOUT:   %T.1 => constants.%T
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: specific @GenericInterface(@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:   %.1 => constants.%.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: specific @F.2(constants.%T) {
 // CHECK:STDOUT:   %T => constants.%T
 // CHECK:STDOUT: }

+ 6 - 1
toolchain/check/testdata/impl/fail_extend_partially_defined_interface.carbon

@@ -63,7 +63,10 @@ interface I {
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C.2 as %.1;
+// CHECK:STDOUT: generic impl @impl(@I.%Self: %.1) {
+// CHECK:STDOUT:
+// CHECK:STDOUT:   impl: %C.2 as %.1;
+// CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: generic class @C(@I.%Self: %.1) {
 // CHECK:STDOUT: !definition:
@@ -82,3 +85,5 @@ interface I {
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @C(constants.%Self) {}
 // CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl(constants.%Self) {}
+// CHECK:STDOUT:

+ 17 - 9
toolchain/check/testdata/impl/impl_forall.carbon

@@ -56,8 +56,8 @@ impl forall [T:! type] T as Simple {
 // 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: type = bind_symbolic_name T 0, %T.param [symbolic = constants.%T]
-// CHECK:STDOUT:     %T.ref: type = name_ref T, %T [symbolic = constants.%T]
+// CHECK:STDOUT:     %T.loc15: type = bind_symbolic_name T 0, %T.param [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:     %T.ref: type = name_ref T, %T.loc15 [symbolic = %T.1 (constants.%T)]
 // CHECK:STDOUT:     %Simple.ref: type = name_ref Simple, file.%Simple.decl [template = constants.%.1]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
@@ -73,13 +73,17 @@ impl forall [T:! type] T as Simple {
 // CHECK:STDOUT:   witness = (%F.decl)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %T as %.1 {
-// CHECK:STDOUT:   %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {} {}
-// CHECK:STDOUT:   %.loc15: <witness> = interface_witness (%F.decl) [template = constants.%.5]
+// CHECK:STDOUT: 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: !members:
-// CHECK:STDOUT:   .F = %F.decl
-// CHECK:STDOUT:   witness = %.loc15
+// CHECK:STDOUT:   impl: %T as %.1 {
+// CHECK:STDOUT:     %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {} {}
+// CHECK:STDOUT:     %.loc15: <witness> = interface_witness (%F.decl) [template = constants.%.5]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .F = %F.decl
+// CHECK:STDOUT:     witness = %.loc15
+// CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: generic fn @F.1(@Simple.%Self: %.1) {
@@ -87,7 +91,7 @@ impl forall [T:! type] T as Simple {
 // CHECK:STDOUT:   fn();
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: generic fn @F.2(@impl.%T: type) {
+// CHECK:STDOUT: generic fn @F.2(@impl.%T.loc15: type) {
 // CHECK:STDOUT: !definition:
 // CHECK:STDOUT:
 // CHECK:STDOUT:   fn() {
@@ -98,6 +102,10 @@ impl forall [T:! type] T as Simple {
 // 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:
 // CHECK:STDOUT: specific @F.2(constants.%T) {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @F.1(constants.%T) {}

+ 7 - 5
toolchain/check/testdata/impl/lookup/fail_todo_undefined_impl.carbon

@@ -82,9 +82,9 @@ impl C as I {
 // CHECK:STDOUT:     %.loc19_11.2: type = converted %int.make_type_32, %.loc19_11.1 [template = i32]
 // CHECK:STDOUT:     %return: ref i32 = var <return slot>
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   impl_decl @impl {} {
+// CHECK:STDOUT:   impl_decl @impl.2 {} {
 // CHECK:STDOUT:     %C.ref: type = name_ref C, file.%C.decl [template = constants.%C]
-// CHECK:STDOUT:     %I.ref.loc27: type = name_ref I, file.%I.decl [template = constants.%.1]
+// CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [template = constants.%.1]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -99,7 +99,9 @@ impl C as I {
 // CHECK:STDOUT:   witness = (%F.decl)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.1 {
+// CHECK:STDOUT: impl @impl.1: %C as %.1;
+// CHECK:STDOUT:
+// CHECK:STDOUT: impl @impl.2: %C as %.1 {
 // CHECK:STDOUT:   %F.decl: %F.type.3 = fn_decl @F.3 [template = constants.%F.3] {} {}
 // CHECK:STDOUT:   %.loc27: <witness> = interface_witness (%F.decl) [template = constants.%.8]
 // CHECK:STDOUT:
@@ -109,8 +111,8 @@ impl C as I {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
-// CHECK:STDOUT:   impl_decl @impl {} {
-// CHECK:STDOUT:     %I.ref.loc16: type = name_ref I, file.%I.decl [template = constants.%.1]
+// CHECK:STDOUT:   impl_decl @impl.1 {} {
+// CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [template = constants.%.1]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc17: <witness> = complete_type_witness %.5 [template = constants.%.6]
 // CHECK:STDOUT:

+ 19 - 19
toolchain/check/testdata/impl/lookup/import.carbon

@@ -120,18 +120,18 @@ fn G(c: Impl.C) {
 // CHECK:STDOUT: --- use.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %.1: type = interface_type @HasF [template]
+// CHECK:STDOUT:   %Self: %.1 = bind_symbolic_name Self 0 [symbolic]
 // CHECK:STDOUT:   %C: type = class_type @C [template]
-// CHECK:STDOUT:   %.1: type = struct_type {} [template]
-// CHECK:STDOUT:   %.2: <witness> = complete_type_witness %.1 [template]
-// CHECK:STDOUT:   %.3: type = interface_type @HasF [template]
-// CHECK:STDOUT:   %Self: %.3 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT:   %.2: type = struct_type {} [template]
+// CHECK:STDOUT:   %.3: <witness> = complete_type_witness %.2 [template]
 // CHECK:STDOUT:   %G.type: type = fn_type @G [template]
 // CHECK:STDOUT:   %.4: type = tuple_type () [template]
 // CHECK:STDOUT:   %G: %G.type = struct_value () [template]
-// CHECK:STDOUT:   %.5: type = ptr_type %.1 [template]
+// CHECK:STDOUT:   %.5: type = ptr_type %.2 [template]
 // CHECK:STDOUT:   %F.type.1: type = fn_type @F.1 [template]
 // CHECK:STDOUT:   %F.1: %F.type.1 = struct_value () [template]
-// CHECK:STDOUT:   %.6: type = assoc_entity_type %.3, %F.type.1 [template]
+// CHECK:STDOUT:   %.6: type = assoc_entity_type %.1, %F.type.1 [template]
 // CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, imports.%import_ref.8 [template]
 // CHECK:STDOUT:   %F.type.2: type = fn_type @F.2 [template]
 // CHECK:STDOUT:   %F.2: %F.type.2 = struct_value () [template]
@@ -154,13 +154,13 @@ fn G(c: Impl.C) {
 // CHECK:STDOUT:     .HasF = %import_ref.7
 // CHECK:STDOUT:     import Impl//default
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.1 = import_ref Impl//default, inst+15, unloaded
-// CHECK:STDOUT:   %import_ref.2 = import_ref Impl//default, inst+5, unloaded
-// CHECK:STDOUT:   %import_ref.3: %.6 = import_ref Impl//default, inst+12, loaded [template = constants.%.7]
-// CHECK:STDOUT:   %import_ref.4 = import_ref Impl//default, inst+7, unloaded
+// CHECK:STDOUT:   %import_ref.1 = import_ref Impl//default, inst+5, unloaded
+// CHECK:STDOUT:   %import_ref.2: %.6 = import_ref Impl//default, inst+12, loaded [template = constants.%.7]
+// CHECK:STDOUT:   %import_ref.3 = import_ref Impl//default, inst+7, unloaded
+// CHECK:STDOUT:   %import_ref.4 = import_ref Impl//default, inst+15, unloaded
 // CHECK:STDOUT:   %import_ref.5: <witness> = import_ref Impl//default, inst+25, loaded [template = constants.%.8]
 // CHECK:STDOUT:   %import_ref.6: type = import_ref Impl//default, inst+14, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.7: type = import_ref Impl//default, inst+3, loaded [template = constants.%.3]
+// CHECK:STDOUT:   %import_ref.7: type = import_ref Impl//default, inst+3, loaded [template = constants.%.1]
 // CHECK:STDOUT:   %import_ref.8 = import_ref Impl//default, inst+7, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -184,33 +184,33 @@ fn G(c: Impl.C) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @HasF {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = imports.%import_ref.2
-// CHECK:STDOUT:   .F = imports.%import_ref.3
-// CHECK:STDOUT:   witness = (imports.%import_ref.4)
+// CHECK:STDOUT:   .Self = imports.%import_ref.1
+// CHECK:STDOUT:   .F = imports.%import_ref.2
+// CHECK:STDOUT:   witness = (imports.%import_ref.3)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.3 {
+// CHECK:STDOUT: impl @impl: %C as %.1 {
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   witness = imports.%import_ref.5
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = imports.%import_ref.1
+// CHECK:STDOUT:   .Self = imports.%import_ref.4
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @G(%c: %C) {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %c.ref: %C = name_ref c, %c
 // CHECK:STDOUT:   %Impl.ref.loc5: <namespace> = name_ref Impl, imports.%Impl [template = imports.%Impl]
-// CHECK:STDOUT:   %HasF.ref: type = name_ref HasF, imports.%import_ref.7 [template = constants.%.3]
-// CHECK:STDOUT:   %F.ref: %.6 = name_ref F, imports.%import_ref.3 [template = constants.%.7]
+// CHECK:STDOUT:   %HasF.ref: type = name_ref HasF, imports.%import_ref.7 [template = constants.%.1]
+// CHECK:STDOUT:   %F.ref: %.6 = name_ref F, imports.%import_ref.2 [template = constants.%.7]
 // CHECK:STDOUT:   %.loc5: %F.type.1 = interface_witness_access imports.%import_ref.5, element0 [template = constants.%F.2]
 // CHECK:STDOUT:   %F.call: init %.4 = call %.loc5()
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: generic fn @F.1(constants.%Self: %.3) {
+// CHECK:STDOUT: generic fn @F.1(constants.%Self: %.1) {
 // CHECK:STDOUT:
 // CHECK:STDOUT:   fn();
 // CHECK:STDOUT: }

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

@@ -0,0 +1,434 @@
+// 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/no_prelude/impl_forall.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/impl/lookup/no_prelude/impl_forall.carbon
+
+// --- fail_todo_impl_forall.carbon
+
+class A(T:! type) {
+  var n: T;
+}
+
+interface I(U:! type) {
+  fn F[self: Self]() -> U;
+}
+
+impl forall [V:! type] A(V) as I(V) {
+  fn F[self: Self]() -> V {
+    return self.n;
+  }
+}
+
+fn TestGeneric[W:! type](a: A(W)) -> W {
+  // CHECK:STDERR: fail_todo_impl_forall.carbon:[[@LINE+4]]:10: error: cannot access member of interface `I` in type `A` that does not implement that interface
+  // CHECK:STDERR:   return a.(I(W).F)();
+  // CHECK:STDERR:          ^~~~~~~~~~
+  // CHECK:STDERR:
+  return a.(I(W).F)();
+}
+
+fn TestSpecific(a: A({})) -> {} {
+  // CHECK:STDERR: fail_todo_impl_forall.carbon:[[@LINE+3]]:10: error: cannot access member of interface `I` in type `A` that does not implement that interface
+  // CHECK:STDERR:   return a.(I({}).F)();
+  // CHECK:STDERR:          ^~~~~~~~~~~
+  return a.(I({}).F)();
+}
+
+// CHECK:STDOUT: --- fail_todo_impl_forall.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T 0 [symbolic]
+// CHECK:STDOUT:   %A.type: type = generic_class_type @A [template]
+// CHECK:STDOUT:   %.1: type = tuple_type () [template]
+// CHECK:STDOUT:   %A.1: %A.type = struct_value () [template]
+// CHECK:STDOUT:   %A.2: type = class_type @A, @A(%T) [symbolic]
+// CHECK:STDOUT:   %.2: type = unbound_element_type %A.2, %T [symbolic]
+// CHECK:STDOUT:   %.3: type = struct_type {.n: %T} [symbolic]
+// CHECK:STDOUT:   %.4: <witness> = complete_type_witness %.3 [symbolic]
+// CHECK:STDOUT:   %U: type = bind_symbolic_name U 0 [symbolic]
+// CHECK:STDOUT:   %I.type: type = generic_interface_type @I [template]
+// CHECK:STDOUT:   %I: %I.type = struct_value () [template]
+// CHECK:STDOUT:   %.5: type = interface_type @I, @I(%U) [symbolic]
+// CHECK:STDOUT:   %Self: %.5 = bind_symbolic_name Self 1 [symbolic]
+// CHECK:STDOUT:   %F.type.1: type = fn_type @F.1, @I(%U) [symbolic]
+// CHECK:STDOUT:   %F.1: %F.type.1 = struct_value () [symbolic]
+// CHECK:STDOUT:   %.6: type = assoc_entity_type %.5, %F.type.1 [symbolic]
+// CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, @I.%F.decl [symbolic]
+// CHECK:STDOUT:   %V: type = bind_symbolic_name V 0 [symbolic]
+// CHECK:STDOUT:   %A.3: type = class_type @A, @A(%V) [symbolic]
+// CHECK:STDOUT:   %.8: 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.3: type = fn_type @F.1, @I(%V) [symbolic]
+// CHECK:STDOUT:   %F.3: %F.type.3 = struct_value () [symbolic]
+// CHECK:STDOUT:   %.9: type = assoc_entity_type %.8, %F.type.3 [symbolic]
+// CHECK:STDOUT:   %.10: %.9 = assoc_entity element0, @I.%F.decl [symbolic]
+// CHECK:STDOUT:   %.11: <witness> = interface_witness (%F.2) [template]
+// CHECK:STDOUT:   %.12: type = unbound_element_type %A.3, %V [symbolic]
+// CHECK:STDOUT:   %.13: type = struct_type {.n: %V} [symbolic]
+// CHECK:STDOUT:   %.14: <witness> = complete_type_witness %.13 [symbolic]
+// CHECK:STDOUT:   %.15: type = ptr_type %.13 [symbolic]
+// CHECK:STDOUT:   %W: type = bind_symbolic_name W 0 [symbolic]
+// CHECK:STDOUT:   %A.4: type = class_type @A, @A(%W) [symbolic]
+// CHECK:STDOUT:   %TestGeneric.type: type = fn_type @TestGeneric [template]
+// CHECK:STDOUT:   %TestGeneric: %TestGeneric.type = struct_value () [template]
+// CHECK:STDOUT:   %.16: type = unbound_element_type %A.4, %W [symbolic]
+// CHECK:STDOUT:   %.17: type = struct_type {.n: %W} [symbolic]
+// CHECK:STDOUT:   %.18: <witness> = complete_type_witness %.17 [symbolic]
+// CHECK:STDOUT:   %.19: type = ptr_type %.17 [symbolic]
+// CHECK:STDOUT:   %.20: type = interface_type @I, @I(%W) [symbolic]
+// CHECK:STDOUT:   %F.type.4: type = fn_type @F.1, @I(%W) [symbolic]
+// CHECK:STDOUT:   %F.4: %F.type.4 = struct_value () [symbolic]
+// CHECK:STDOUT:   %.21: type = assoc_entity_type %.20, %F.type.4 [symbolic]
+// CHECK:STDOUT:   %.22: %.21 = assoc_entity element0, @I.%F.decl [symbolic]
+// CHECK:STDOUT:   %.23: type = struct_type {} [template]
+// CHECK:STDOUT:   %A.5: type = class_type @A, @A(%.23) [template]
+// CHECK:STDOUT:   %TestSpecific.type: type = fn_type @TestSpecific [template]
+// CHECK:STDOUT:   %TestSpecific: %TestSpecific.type = struct_value () [template]
+// CHECK:STDOUT:   %.24: type = unbound_element_type %A.5, %.23 [template]
+// CHECK:STDOUT:   %.25: type = struct_type {.n: %.23} [template]
+// CHECK:STDOUT:   %.26: <witness> = complete_type_witness %.25 [template]
+// CHECK:STDOUT:   %.27: type = struct_type {.n: %.1} [template]
+// CHECK:STDOUT:   %.28: type = ptr_type %.25 [template]
+// CHECK:STDOUT:   %.29: type = interface_type @I, @I(%.23) [template]
+// CHECK:STDOUT:   %F.type.5: type = fn_type @F.1, @I(%.23) [template]
+// CHECK:STDOUT:   %F.5: %F.type.5 = struct_value () [template]
+// CHECK:STDOUT:   %.30: type = assoc_entity_type %.29, %F.type.5 [template]
+// CHECK:STDOUT:   %.31: %.30 = assoc_entity element0, @I.%F.decl [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .A = %A.decl
+// CHECK:STDOUT:     .I = %I.decl
+// CHECK:STDOUT:     .TestGeneric = %TestGeneric.decl
+// CHECK:STDOUT:     .TestSpecific = %TestSpecific.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %A.decl: %A.type = class_decl @A [template = constants.%A.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.loc2: type = bind_symbolic_name T 0, %T.param [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %I.decl: %I.type = interface_decl @I [template = constants.%I] {
+// CHECK:STDOUT:     %U.patt: type = symbolic_binding_pattern U 0
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %U.param: type = param U, runtime_param<invalid>
+// CHECK:STDOUT:     %U.loc6: type = bind_symbolic_name U 0, %U.param [symbolic = %U.1 (constants.%U)]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   impl_decl @impl {
+// CHECK:STDOUT:     %V.patt: type = symbolic_binding_pattern V 0
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %V.param: type = param V, runtime_param<invalid>
+// CHECK:STDOUT:     %V.loc10: type = bind_symbolic_name V 0, %V.param [symbolic = %V.1 (constants.%V)]
+// CHECK:STDOUT:     %A.ref: %A.type = name_ref A, file.%A.decl [template = constants.%A.1]
+// CHECK:STDOUT:     %V.ref.loc10_26: type = name_ref V, %V.loc10 [symbolic = %V.1 (constants.%V)]
+// CHECK:STDOUT:     %A.loc10: type = class_type @A, @A(constants.%V) [symbolic = %A.1 (constants.%A.3)]
+// CHECK:STDOUT:     %I.ref: %I.type = name_ref I, file.%I.decl [template = constants.%I]
+// CHECK:STDOUT:     %V.ref.loc10_34: type = name_ref V, %V.loc10 [symbolic = %V.1 (constants.%V)]
+// CHECK:STDOUT:     %.loc10_33: type = interface_type @I, @I(constants.%V) [symbolic = %.1 (constants.%.8)]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %TestGeneric.decl: %TestGeneric.type = fn_decl @TestGeneric [template = constants.%TestGeneric] {
+// CHECK:STDOUT:     %W.patt: type = symbolic_binding_pattern W 0
+// CHECK:STDOUT:     %a.patt: @TestGeneric.%A.1 (%A.4) = binding_pattern a
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %W.param: type = param W, runtime_param<invalid>
+// CHECK:STDOUT:     %W.loc16: type = bind_symbolic_name W 0, %W.param [symbolic = %W.1 (constants.%W)]
+// CHECK:STDOUT:     %A.ref: %A.type = name_ref A, file.%A.decl [template = constants.%A.1]
+// CHECK:STDOUT:     %W.ref.loc16_31: type = name_ref W, %W.loc16 [symbolic = %W.1 (constants.%W)]
+// CHECK:STDOUT:     %A.loc16: type = class_type @A, @A(constants.%W) [symbolic = %A.1 (constants.%A.4)]
+// CHECK:STDOUT:     %a.param: @TestGeneric.%A.1 (%A.4) = param a, runtime_param0
+// CHECK:STDOUT:     %a: @TestGeneric.%A.1 (%A.4) = bind_name a, %a.param
+// CHECK:STDOUT:     %W.ref.loc16_38: type = name_ref W, %W.loc16 [symbolic = %W.1 (constants.%W)]
+// CHECK:STDOUT:     %return: ref @TestGeneric.%W.1 (%W) = var <return slot>
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %TestSpecific.decl: %TestSpecific.type = fn_decl @TestSpecific [template = constants.%TestSpecific] {
+// CHECK:STDOUT:     %a.patt: %A.5 = binding_pattern a
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %A.ref: %A.type = name_ref A, file.%A.decl [template = constants.%A.1]
+// CHECK:STDOUT:     %.loc24_23: %.23 = struct_literal ()
+// CHECK:STDOUT:     %.loc24_21: type = converted %.loc24_23, constants.%.23 [template = constants.%.23]
+// CHECK:STDOUT:     %A: type = class_type @A, @A(constants.%.23) [template = constants.%A.5]
+// CHECK:STDOUT:     %a.param: %A.5 = param a, runtime_param0
+// CHECK:STDOUT:     %a: %A.5 = bind_name a, %a.param
+// CHECK:STDOUT:     %.loc24_31.1: %.23 = struct_literal ()
+// CHECK:STDOUT:     %.loc24_31.2: type = converted %.loc24_31.1, constants.%.23 [template = constants.%.23]
+// CHECK:STDOUT:     %return: ref %.23 = var <return slot>
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic interface @I(%U.loc6: type) {
+// CHECK:STDOUT:   %U.1: type = bind_symbolic_name U 0 [symbolic = %U.1 (constants.%U)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %.1: type = interface_type @I, @I(%U.1) [symbolic = %.1 (constants.%.5)]
+// CHECK:STDOUT:   %Self.2: %.5 = bind_symbolic_name Self 1 [symbolic = %Self.2 (constants.%Self)]
+// CHECK:STDOUT:   %F.type: type = fn_type @F.1, @I(%U.1) [symbolic = %F.type (constants.%F.type.1)]
+// CHECK:STDOUT:   %F: @I.%F.type (%F.type.1) = struct_value () [symbolic = %F (constants.%F.1)]
+// CHECK:STDOUT:   %.2: type = assoc_entity_type @I.%.1 (%.5), @I.%F.type (%F.type.1) [symbolic = %.2 (constants.%.6)]
+// CHECK:STDOUT:   %.3: @I.%.2 (%.6) = assoc_entity element0, %F.decl [symbolic = %.3 (constants.%.7)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   interface {
+// CHECK:STDOUT:     %Self.1: @I.%.1 (%.5) = bind_symbolic_name Self 1 [symbolic = %Self.2 (constants.%Self)]
+// CHECK:STDOUT:     %F.decl: @I.%F.type (%F.type.1) = fn_decl @F.1 [symbolic = @I.%F (constants.%F.1)] {
+// CHECK:STDOUT:       %self.patt: @F.1.%Self (%Self) = binding_pattern self
+// CHECK:STDOUT:     } {
+// CHECK:STDOUT:       %.loc7_14.1: @F.1.%.1 (%.5) = specific_constant @I.%Self.1, @I(constants.%U) [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:       %Self.ref: @F.1.%.1 (%.5) = name_ref Self, %.loc7_14.1 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:       %.loc7_14.2: type = facet_type_access %Self.ref [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:       %.loc7_14.3: type = converted %Self.ref, %.loc7_14.2 [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:       %U.ref: type = name_ref U, @I.%U.loc6 [symbolic = %U (constants.%U)]
+// CHECK:STDOUT:       %return: ref @F.1.%U (%U) = var <return slot>
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:     %.loc7: @I.%.2 (%.6) = assoc_entity element0, %F.decl [symbolic = %.3 (constants.%.7)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .Self = %Self.1
+// CHECK:STDOUT:     .F = %.loc7
+// CHECK:STDOUT:     witness = (%F.decl)
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic impl @impl(%V.loc10: type) {
+// CHECK:STDOUT:   %V.1: type = bind_symbolic_name V 0 [symbolic = %V.1 (constants.%V)]
+// CHECK:STDOUT:   %A.1: type = class_type @A, @A(%V.1) [symbolic = %A.1 (constants.%A.3)]
+// CHECK:STDOUT:   %.1: type = interface_type @I, @I(%V.1) [symbolic = %.1 (constants.%.8)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   impl: %A.3 as %.8 {
+// CHECK:STDOUT:     %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {
+// CHECK:STDOUT:       %self.patt: @F.2.%A (%A.3) = binding_pattern self
+// CHECK:STDOUT:     } {
+// CHECK:STDOUT:       %Self.ref: type = name_ref Self, constants.%A.3 [symbolic = %A (constants.%A.3)]
+// CHECK:STDOUT:       %self.param: @F.2.%A (%A.3) = param self, runtime_param0
+// CHECK:STDOUT:       %self: @F.2.%A (%A.3) = bind_name self, %self.param
+// 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_37: <witness> = interface_witness (%F.decl) [template = constants.%.11]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .F = %F.decl
+// CHECK:STDOUT:     witness = %.loc10_37
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic class @A(%T.loc2: type) {
+// CHECK:STDOUT:   %T.1: type = bind_symbolic_name T 0 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %A: type = class_type @A, @A(%T.1) [symbolic = %A (constants.%A.2)]
+// CHECK:STDOUT:   %.1: type = unbound_element_type @A.%A (%A.2), @A.%T.1 (%T) [symbolic = %.1 (constants.%.2)]
+// CHECK:STDOUT:   %.2: type = struct_type {.n: @A.%T.1 (%T)} [symbolic = %.2 (constants.%.3)]
+// CHECK:STDOUT:   %.3: <witness> = complete_type_witness @A.%.2 (%.3) [symbolic = %.3 (constants.%.4)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   class {
+// CHECK:STDOUT:     %T.ref: type = name_ref T, %T.loc2 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:     %.loc3: @A.%.1 (%.2) = field_decl n, element0 [template]
+// CHECK:STDOUT:     %.loc4: <witness> = complete_type_witness %.3 [symbolic = %.3 (constants.%.4)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .Self = constants.%A.2
+// CHECK:STDOUT:     .n = %.loc3
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F.1(@I.%U.loc6: type, @I.%Self.1: @I.%.1 (%.5)) {
+// CHECK:STDOUT:   %U: type = bind_symbolic_name U 0 [symbolic = %U (constants.%U)]
+// CHECK:STDOUT:   %.1: type = interface_type @I, @I(%U) [symbolic = %.1 (constants.%.5)]
+// CHECK:STDOUT:   %Self: %.5 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn[%self: @F.1.%Self (%Self)]() -> @F.1.%U (%U);
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F.2(@impl.%V.loc10: type) {
+// CHECK:STDOUT:   %V: type = bind_symbolic_name V 0 [symbolic = %V (constants.%V)]
+// CHECK:STDOUT:   %A: type = class_type @A, @A(%V) [symbolic = %A (constants.%A.3)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %.1: type = unbound_element_type @F.2.%A (%A.3), @F.2.%V (%V) [symbolic = %.1 (constants.%.12)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn[%self: @F.2.%A (%A.3)]() -> @F.2.%V (%V) {
+// CHECK:STDOUT:   !entry:
+// CHECK:STDOUT:     %self.ref: @F.2.%A (%A.3) = name_ref self, %self
+// CHECK:STDOUT:     %n.ref: @F.2.%.1 (%.12) = name_ref n, @A.%.loc3 [template = @A.%.loc3]
+// CHECK:STDOUT:     %.loc12_16.1: ref @F.2.%V (%V) = class_element_access %self.ref, element0
+// CHECK:STDOUT:     %.loc12_16.2: @F.2.%V (%V) = bind_value %.loc12_16.1
+// CHECK:STDOUT:     return %.loc12_16.2
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @TestGeneric(%W.loc16: type) {
+// CHECK:STDOUT:   %W.1: type = bind_symbolic_name W 0 [symbolic = %W.1 (constants.%W)]
+// CHECK:STDOUT:   %A.1: type = class_type @A, @A(%W.1) [symbolic = %A.1 (constants.%A.4)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %.1: type = interface_type @I, @I(%W.1) [symbolic = %.1 (constants.%.20)]
+// CHECK:STDOUT:   %F.type: type = fn_type @F.1, @I(%W.1) [symbolic = %F.type (constants.%F.type.4)]
+// CHECK:STDOUT:   %.2: type = assoc_entity_type @TestGeneric.%.1 (%.20), @TestGeneric.%F.type (%F.type.4) [symbolic = %.2 (constants.%.21)]
+// CHECK:STDOUT:   %.3: @TestGeneric.%.2 (%.21) = assoc_entity element0, @I.%F.decl [symbolic = %.3 (constants.%.22)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn[%W.loc16: type](%a: @TestGeneric.%A.1 (%A.4)) -> @TestGeneric.%W.1 (%W) {
+// CHECK:STDOUT:   !entry:
+// CHECK:STDOUT:     %a.ref: @TestGeneric.%A.1 (%A.4) = name_ref a, %a
+// CHECK:STDOUT:     %I.ref: %I.type = name_ref I, file.%I.decl [template = constants.%I]
+// CHECK:STDOUT:     %W.ref.loc21: type = name_ref W, %W.loc16 [symbolic = %W.1 (constants.%W)]
+// CHECK:STDOUT:     %.loc21_14: type = interface_type @I, @I(constants.%W) [symbolic = %.1 (constants.%.20)]
+// CHECK:STDOUT:     %.loc21_17: @TestGeneric.%.2 (%.21) = specific_constant @I.%.loc7, @I(constants.%W) [symbolic = %.3 (constants.%.22)]
+// CHECK:STDOUT:     %F.ref: @TestGeneric.%.2 (%.21) = name_ref F, %.loc21_17 [symbolic = %.3 (constants.%.22)]
+// CHECK:STDOUT:     return <error>
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @TestSpecific(%a: %A.5) -> %.23 {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %a.ref: %A.5 = name_ref a, %a
+// CHECK:STDOUT:   %I.ref: %I.type = name_ref I, file.%I.decl [template = constants.%I]
+// CHECK:STDOUT:   %.loc28_16: %.23 = struct_literal ()
+// CHECK:STDOUT:   %.loc28_14.1: type = converted %.loc28_16, constants.%.23 [template = constants.%.23]
+// CHECK:STDOUT:   %.loc28_14.2: type = interface_type @I, @I(constants.%.23) [template = constants.%.29]
+// CHECK:STDOUT:   %.loc28_18: %.30 = specific_constant @I.%.loc7, @I(constants.%.23) [template = constants.%.31]
+// CHECK:STDOUT:   %F.ref: %.30 = name_ref F, %.loc28_18 [template = constants.%.31]
+// CHECK:STDOUT:   return <error>
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @A(constants.%T) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @A(@A.%T.1) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @I(constants.%U) {
+// CHECK:STDOUT:   %U.1 => constants.%U
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @I(@F.1.%U) {
+// CHECK:STDOUT:   %U.1 => constants.%U
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%U, constants.%Self) {
+// CHECK:STDOUT:   %U => constants.%U
+// CHECK:STDOUT:   %.1 => constants.%.5
+// CHECK:STDOUT:   %Self => constants.%Self
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @I(@I.%U.1) {
+// CHECK:STDOUT:   %U.1 => constants.%U
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @A(constants.%V) {
+// CHECK:STDOUT:   %T.1 => constants.%V
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %A => constants.%A.3
+// CHECK:STDOUT:   %.1 => constants.%.12
+// CHECK:STDOUT:   %.2 => constants.%.13
+// CHECK:STDOUT:   %.3 => constants.%.14
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @I(constants.%V) {
+// CHECK:STDOUT:   %U.1 => constants.%V
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %.1 => constants.%.8
+// CHECK:STDOUT:   %Self.2 => constants.%Self
+// CHECK:STDOUT:   %F.type => constants.%F.type.3
+// CHECK:STDOUT:   %F => constants.%F.3
+// CHECK:STDOUT:   %.2 => constants.%.9
+// CHECK:STDOUT:   %.3 => constants.%.10
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @A(@impl.%V.1) {
+// CHECK:STDOUT:   %T.1 => constants.%V
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @I(@impl.%V.1) {
+// CHECK:STDOUT:   %U.1 => constants.%V
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl(constants.%V) {
+// CHECK:STDOUT:   %V.1 => constants.%V
+// CHECK:STDOUT:   %A.1 => constants.%A.3
+// CHECK:STDOUT:   %.1 => constants.%.8
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @A(@F.2.%V) {
+// CHECK:STDOUT:   %T.1 => constants.%V
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.2(constants.%V) {
+// CHECK:STDOUT:   %V => constants.%V
+// CHECK:STDOUT:   %A => constants.%A.3
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%V, constants.%A.3) {
+// CHECK:STDOUT:   %U => constants.%V
+// CHECK:STDOUT:   %.1 => constants.%.8
+// CHECK:STDOUT:   %Self => constants.%A.3
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @A(constants.%W) {
+// CHECK:STDOUT:   %T.1 => constants.%W
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %A => constants.%A.4
+// CHECK:STDOUT:   %.1 => constants.%.16
+// CHECK:STDOUT:   %.2 => constants.%.17
+// CHECK:STDOUT:   %.3 => constants.%.18
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @A(@TestGeneric.%W.1) {
+// CHECK:STDOUT:   %T.1 => constants.%W
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @TestGeneric(constants.%W) {
+// CHECK:STDOUT:   %W.1 => constants.%W
+// CHECK:STDOUT:   %A.1 => constants.%A.4
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @I(constants.%W) {
+// CHECK:STDOUT:   %U.1 => constants.%W
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %.1 => constants.%.20
+// CHECK:STDOUT:   %Self.2 => constants.%Self
+// CHECK:STDOUT:   %F.type => constants.%F.type.4
+// CHECK:STDOUT:   %F => constants.%F.4
+// CHECK:STDOUT:   %.2 => constants.%.21
+// CHECK:STDOUT:   %.3 => constants.%.22
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @I(@TestGeneric.%W.1) {
+// CHECK:STDOUT:   %U.1 => constants.%W
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @A(constants.%.23) {
+// CHECK:STDOUT:   %T.1 => constants.%.23
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %A => constants.%A.5
+// CHECK:STDOUT:   %.1 => constants.%.24
+// CHECK:STDOUT:   %.2 => constants.%.25
+// CHECK:STDOUT:   %.3 => constants.%.26
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @I(constants.%.23) {
+// CHECK:STDOUT:   %U.1 => constants.%.23
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %.1 => constants.%.29
+// CHECK:STDOUT:   %Self.2 => constants.%Self
+// CHECK:STDOUT:   %F.type => constants.%F.type.5
+// CHECK:STDOUT:   %F => constants.%F.5
+// CHECK:STDOUT:   %.2 => constants.%.30
+// CHECK:STDOUT:   %.3 => constants.%.31
+// CHECK:STDOUT: }
+// CHECK:STDOUT:

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

@@ -105,18 +105,18 @@ fn G(c: Impl.C) {
 // CHECK:STDOUT: --- use.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %.1: type = interface_type @HasF [template]
+// CHECK:STDOUT:   %Self: %.1 = bind_symbolic_name Self 0 [symbolic]
 // CHECK:STDOUT:   %C: type = class_type @C [template]
-// CHECK:STDOUT:   %.1: type = struct_type {} [template]
-// CHECK:STDOUT:   %.2: <witness> = complete_type_witness %.1 [template]
-// CHECK:STDOUT:   %.3: type = interface_type @HasF [template]
-// CHECK:STDOUT:   %Self: %.3 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT:   %.2: type = struct_type {} [template]
+// CHECK:STDOUT:   %.3: <witness> = complete_type_witness %.2 [template]
 // CHECK:STDOUT:   %G.type: type = fn_type @G [template]
 // CHECK:STDOUT:   %.4: type = tuple_type () [template]
 // CHECK:STDOUT:   %G: %G.type = struct_value () [template]
-// CHECK:STDOUT:   %.5: type = ptr_type %.1 [template]
+// CHECK:STDOUT:   %.5: type = ptr_type %.2 [template]
 // CHECK:STDOUT:   %F.type.1: type = fn_type @F.1 [template]
 // CHECK:STDOUT:   %F.1: %F.type.1 = struct_value () [template]
-// CHECK:STDOUT:   %.6: type = assoc_entity_type %.3, %F.type.1 [template]
+// CHECK:STDOUT:   %.6: type = assoc_entity_type %.1, %F.type.1 [template]
 // CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, imports.%import_ref.8 [template]
 // CHECK:STDOUT:   %F.type.2: type = fn_type @F.2 [template]
 // CHECK:STDOUT:   %F.2: %F.type.2 = struct_value () [template]
@@ -129,13 +129,13 @@ fn G(c: Impl.C) {
 // CHECK:STDOUT:     .HasF = %import_ref.7
 // CHECK:STDOUT:     import Impl//default
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.1 = import_ref Impl//default, inst+13, unloaded
-// CHECK:STDOUT:   %import_ref.2 = import_ref Impl//default, inst+3, unloaded
-// CHECK:STDOUT:   %import_ref.3: %.6 = import_ref Impl//default, inst+10, loaded [template = constants.%.7]
-// CHECK:STDOUT:   %import_ref.4 = import_ref Impl//default, inst+5, unloaded
+// CHECK:STDOUT:   %import_ref.1 = import_ref Impl//default, inst+3, unloaded
+// CHECK:STDOUT:   %import_ref.2: %.6 = import_ref Impl//default, inst+10, loaded [template = constants.%.7]
+// CHECK:STDOUT:   %import_ref.3 = import_ref Impl//default, inst+5, unloaded
+// CHECK:STDOUT:   %import_ref.4 = import_ref Impl//default, inst+13, unloaded
 // CHECK:STDOUT:   %import_ref.5: <witness> = import_ref Impl//default, inst+23, loaded [template = constants.%.8]
 // CHECK:STDOUT:   %import_ref.6: type = import_ref Impl//default, inst+12, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.7: type = import_ref Impl//default, inst+1, loaded [template = constants.%.3]
+// CHECK:STDOUT:   %import_ref.7: type = import_ref Impl//default, inst+1, loaded [template = constants.%.1]
 // CHECK:STDOUT:   %import_ref.8 = import_ref Impl//default, inst+5, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -157,33 +157,33 @@ fn G(c: Impl.C) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @HasF {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = imports.%import_ref.2
-// CHECK:STDOUT:   .F = imports.%import_ref.3
-// CHECK:STDOUT:   witness = (imports.%import_ref.4)
+// CHECK:STDOUT:   .Self = imports.%import_ref.1
+// CHECK:STDOUT:   .F = imports.%import_ref.2
+// CHECK:STDOUT:   witness = (imports.%import_ref.3)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C as %.3 {
+// CHECK:STDOUT: impl @impl: %C as %.1 {
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   witness = imports.%import_ref.5
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = imports.%import_ref.1
+// CHECK:STDOUT:   .Self = imports.%import_ref.4
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @G(%c: %C) {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %c.ref: %C = name_ref c, %c
 // CHECK:STDOUT:   %Impl.ref.loc5: <namespace> = name_ref Impl, imports.%Impl [template = imports.%Impl]
-// CHECK:STDOUT:   %HasF.ref: type = name_ref HasF, imports.%import_ref.7 [template = constants.%.3]
-// CHECK:STDOUT:   %F.ref: %.6 = name_ref F, imports.%import_ref.3 [template = constants.%.7]
+// CHECK:STDOUT:   %HasF.ref: type = name_ref HasF, imports.%import_ref.7 [template = constants.%.1]
+// CHECK:STDOUT:   %F.ref: %.6 = name_ref F, imports.%import_ref.2 [template = constants.%.7]
 // CHECK:STDOUT:   %.loc5: %F.type.1 = interface_witness_access imports.%import_ref.5, element0 [template = constants.%F.2]
 // CHECK:STDOUT:   %F.call: init %.4 = call %.loc5()
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: generic fn @F.1(constants.%Self: %.3) {
+// CHECK:STDOUT: generic fn @F.1(constants.%Self: %.1) {
 // CHECK:STDOUT:
 // CHECK:STDOUT:   fn();
 // CHECK:STDOUT: }

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

@@ -0,0 +1,335 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// AUTOUPDATE
+// TIP: To test this file alone, run:
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/impl/no_prelude/generic_redeclaration.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/impl/no_prelude/generic_redeclaration.carbon
+
+// --- same_self_and_interface.carbon
+
+library "[[@TEST_NAME]]";
+
+interface I {}
+interface J {}
+interface K {}
+
+impl forall [T:! I] T as K;
+impl forall [T:! J] T as K;
+
+// These are two different impls, so this is not a redefinition, even though the
+// self type and constraint type are the same.
+impl forall [T:! I] T as K {}
+impl forall [T:! J] T as K {}
+
+// --- fail_same_self_and_interface_redefined.carbon
+
+library "[[@TEST_NAME]]";
+
+interface I {}
+interface J {}
+
+impl forall [T:! I] T as J {}
+// CHECK:STDERR: fail_same_self_and_interface_redefined.carbon:[[@LINE+6]]:1: error: redefinition of `impl T as J`
+// CHECK:STDERR: impl forall [T:! I] T as J {}
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR: fail_same_self_and_interface_redefined.carbon:[[@LINE-4]]:1: note: previous definition was here
+// CHECK:STDERR: impl forall [T:! I] T as J {}
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
+impl forall [T:! I] T as J {}
+
+// --- same_type_different_spelling.carbon
+
+library "[[@TEST_NAME]]";
+
+class C;
+interface I {}
+
+// We accept this because these two types are spelled differently, even though
+// they evaluate to the same type constant. Any use of this impl will be
+// ambiguous unless resolved by a `match_first` or similar.
+//
+// TODO: Produce a warning or maybe an error when this happens in a non-generic
+// impl.
+impl C as I {}
+impl (C, C).0 as I {}
+
+// CHECK:STDOUT: --- same_self_and_interface.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %.1: type = interface_type @I [template]
+// CHECK:STDOUT:   %Self.1: %.1 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT:   %.2: type = interface_type @J [template]
+// CHECK:STDOUT:   %Self.2: %.2 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT:   %.3: type = interface_type @K [template]
+// CHECK:STDOUT:   %Self.3: %.3 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT:   %T.1: %.1 = bind_symbolic_name T 0 [symbolic]
+// CHECK:STDOUT:   %T.2: %.2 = bind_symbolic_name T 0 [symbolic]
+// CHECK:STDOUT:   %.4: type = tuple_type () [template]
+// CHECK:STDOUT:   %.5: <witness> = interface_witness () [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .I = %I.decl
+// CHECK:STDOUT:     .J = %J.decl
+// CHECK:STDOUT:     .K = %K.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %I.decl: type = interface_decl @I [template = constants.%.1] {} {}
+// CHECK:STDOUT:   %J.decl: type = interface_decl @J [template = constants.%.2] {} {}
+// CHECK:STDOUT:   %K.decl: type = interface_decl @K [template = constants.%.3] {} {}
+// CHECK:STDOUT:   impl_decl @impl.1 {
+// CHECK:STDOUT:     %T.patt: %.1 = symbolic_binding_pattern T 0
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [template = constants.%.1]
+// CHECK:STDOUT:     %T.param: %.1 = param T, runtime_param<invalid>
+// CHECK:STDOUT:     %T.loc8: %.1 = bind_symbolic_name T 0, %T.param [symbolic = %T.1 (constants.%T.1)]
+// CHECK:STDOUT:     %T.ref: %.1 = name_ref T, %T.loc8 [symbolic = %T.1 (constants.%T.1)]
+// CHECK:STDOUT:     %.loc8_21.1: type = facet_type_access %T.ref [symbolic = %T.1 (constants.%T.1)]
+// CHECK:STDOUT:     %.loc8_21.2: type = converted %T.ref, %.loc8_21.1 [symbolic = %T.1 (constants.%T.1)]
+// CHECK:STDOUT:     %K.ref: type = name_ref K, file.%K.decl [template = constants.%.3]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   impl_decl @impl.2 {
+// CHECK:STDOUT:     %T.patt: %.2 = symbolic_binding_pattern T 0
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %J.ref: type = name_ref J, file.%J.decl [template = constants.%.2]
+// CHECK:STDOUT:     %T.param: %.2 = param T, runtime_param<invalid>
+// CHECK:STDOUT:     %T.loc9: %.2 = bind_symbolic_name T 0, %T.param [symbolic = %T.1 (constants.%T.2)]
+// CHECK:STDOUT:     %T.ref: %.2 = name_ref T, %T.loc9 [symbolic = %T.1 (constants.%T.2)]
+// CHECK:STDOUT:     %.loc9_21.1: type = facet_type_access %T.ref [symbolic = %T.1 (constants.%T.2)]
+// CHECK:STDOUT:     %.loc9_21.2: type = converted %T.ref, %.loc9_21.1 [symbolic = %T.1 (constants.%T.2)]
+// CHECK:STDOUT:     %K.ref: type = name_ref K, file.%K.decl [template = constants.%.3]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   impl_decl @impl.3 {
+// CHECK:STDOUT:     %T.patt: %.1 = symbolic_binding_pattern T 0
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [template = constants.%.1]
+// CHECK:STDOUT:     %T.param: %.1 = param T, runtime_param<invalid>
+// CHECK:STDOUT:     %T.loc13: %.1 = bind_symbolic_name T 0, %T.param [symbolic = %T.1 (constants.%T.1)]
+// CHECK:STDOUT:     %T.ref: %.1 = name_ref T, %T.loc13 [symbolic = %T.1 (constants.%T.1)]
+// CHECK:STDOUT:     %.loc13_21.1: type = facet_type_access %T.ref [symbolic = %T.1 (constants.%T.1)]
+// CHECK:STDOUT:     %.loc13_21.2: type = converted %T.ref, %.loc13_21.1 [symbolic = %T.1 (constants.%T.1)]
+// CHECK:STDOUT:     %K.ref: type = name_ref K, file.%K.decl [template = constants.%.3]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   impl_decl @impl.4 {
+// CHECK:STDOUT:     %T.patt: %.2 = symbolic_binding_pattern T 0
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %J.ref: type = name_ref J, file.%J.decl [template = constants.%.2]
+// CHECK:STDOUT:     %T.param: %.2 = param T, runtime_param<invalid>
+// CHECK:STDOUT:     %T.loc14: %.2 = bind_symbolic_name T 0, %T.param [symbolic = %T.1 (constants.%T.2)]
+// CHECK:STDOUT:     %T.ref: %.2 = name_ref T, %T.loc14 [symbolic = %T.1 (constants.%T.2)]
+// CHECK:STDOUT:     %.loc14_21.1: type = facet_type_access %T.ref [symbolic = %T.1 (constants.%T.2)]
+// CHECK:STDOUT:     %.loc14_21.2: type = converted %T.ref, %.loc14_21.1 [symbolic = %T.1 (constants.%T.2)]
+// CHECK:STDOUT:     %K.ref: type = name_ref K, file.%K.decl [template = constants.%.3]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @I {
+// CHECK:STDOUT:   %Self: %.1 = bind_symbolic_name Self 0 [symbolic = constants.%Self.1]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   witness = ()
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @J {
+// CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = constants.%Self.2]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   witness = ()
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @K {
+// CHECK:STDOUT:   %Self: %.3 = bind_symbolic_name Self 0 [symbolic = constants.%Self.3]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   witness = ()
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic impl @impl.1(%T.loc8: %.1) {
+// CHECK:STDOUT:   %T.1: %.1 = bind_symbolic_name T 0 [symbolic = %T.1 (constants.%T.1)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   impl: %T.1 as %.3;
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic impl @impl.2(%T.loc9: %.2) {
+// CHECK:STDOUT:   %T.1: %.2 = bind_symbolic_name T 0 [symbolic = %T.1 (constants.%T.2)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   impl: %T.2 as %.3;
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic impl @impl.3(%T.loc13: %.1) {
+// CHECK:STDOUT:   %T.1: %.1 = bind_symbolic_name T 0 [symbolic = %T.1 (constants.%T.1)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   impl: %T.1 as %.3 {
+// CHECK:STDOUT:     %.loc13_28: <witness> = interface_witness () [template = constants.%.5]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     witness = %.loc13_28
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic impl @impl.4(%T.loc14: %.2) {
+// CHECK:STDOUT:   %T.1: %.2 = bind_symbolic_name T 0 [symbolic = %T.1 (constants.%T.2)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   impl: %T.2 as %.3 {
+// CHECK:STDOUT:     %.loc14_28: <witness> = interface_witness () [template = constants.%.5]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     witness = %.loc14_28
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl.1(constants.%T.1) {
+// CHECK:STDOUT:   %T.1 => constants.%T.1
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl.2(constants.%T.2) {
+// CHECK:STDOUT:   %T.1 => constants.%T.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl.3(constants.%T.1) {
+// CHECK:STDOUT:   %T.1 => constants.%T.1
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl.4(constants.%T.2) {
+// CHECK:STDOUT:   %T.1 => constants.%T.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_same_self_and_interface_redefined.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %.1: type = interface_type @I [template]
+// CHECK:STDOUT:   %Self.1: %.1 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT:   %.2: type = interface_type @J [template]
+// CHECK:STDOUT:   %Self.2: %.2 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT:   %T: %.1 = bind_symbolic_name T 0 [symbolic]
+// CHECK:STDOUT:   %.3: type = tuple_type () [template]
+// CHECK:STDOUT:   %.4: <witness> = interface_witness () [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .I = %I.decl
+// CHECK:STDOUT:     .J = %J.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %I.decl: type = interface_decl @I [template = constants.%.1] {} {}
+// CHECK:STDOUT:   %J.decl: type = interface_decl @J [template = constants.%.2] {} {}
+// CHECK:STDOUT:   impl_decl @impl {
+// CHECK:STDOUT:     %T.patt: %.1 = symbolic_binding_pattern T 0
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %I.ref.loc7: type = name_ref I, file.%I.decl [template = constants.%.1]
+// CHECK:STDOUT:     %T.param.loc7: %.1 = param T, runtime_param<invalid>
+// CHECK:STDOUT:     %T.loc7: %.1 = bind_symbolic_name T 0, %T.param.loc7 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:     %T.ref.loc7: %.1 = name_ref T, %T.loc7 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:     %.loc7_21.1: type = facet_type_access %T.ref.loc7 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:     %.loc7_21.2: type = converted %T.ref.loc7, %.loc7_21.1 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:     %J.ref.loc7: type = name_ref J, file.%J.decl [template = constants.%.2]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   impl_decl @impl {
+// CHECK:STDOUT:     %T.patt: %.1 = symbolic_binding_pattern T 0
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %I.ref.loc14: type = name_ref I, file.%I.decl [template = constants.%.1]
+// CHECK:STDOUT:     %T.param.loc14: %.1 = param T, runtime_param<invalid>
+// CHECK:STDOUT:     %T.loc14: %.1 = bind_symbolic_name T 0, %T.param.loc14 [symbolic = constants.%T]
+// CHECK:STDOUT:     %T.ref.loc14: %.1 = name_ref T, %T.loc14 [symbolic = constants.%T]
+// CHECK:STDOUT:     %.loc14_21.1: type = facet_type_access %T.ref.loc14 [symbolic = constants.%T]
+// CHECK:STDOUT:     %.loc14_21.2: type = converted %T.ref.loc14, %.loc14_21.1 [symbolic = constants.%T]
+// CHECK:STDOUT:     %J.ref.loc14: type = name_ref J, file.%J.decl [template = constants.%.2]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @I {
+// CHECK:STDOUT:   %Self: %.1 = bind_symbolic_name Self 0 [symbolic = constants.%Self.1]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   witness = ()
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @J {
+// CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic = constants.%Self.2]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   witness = ()
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic impl @impl(%T.loc7: %.1) {
+// CHECK:STDOUT:   %T.1: %.1 = bind_symbolic_name T 0 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   impl: %T as %.2 {
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     witness = <unexpected>.inst+21.loc7_28
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl(constants.%T) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- same_type_different_spelling.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = interface_type @I [template]
+// CHECK:STDOUT:   %Self: %.1 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %.3: <witness> = interface_witness () [template]
+// CHECK:STDOUT:   %.4: type = tuple_type (type, type) [template]
+// CHECK:STDOUT:   %.5: i32 = int_literal 0 [template]
+// CHECK:STDOUT:   %.6: type = ptr_type %.4 [template]
+// CHECK:STDOUT:   %tuple: %.4 = tuple_value (%C, %C) [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .I = %I.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {} {}
+// CHECK:STDOUT:   %I.decl: type = interface_decl @I [template = constants.%.1] {} {}
+// CHECK:STDOUT:   impl_decl @impl.1 {} {
+// CHECK:STDOUT:     %C.ref: type = name_ref C, file.%C.decl [template = constants.%C]
+// CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [template = constants.%.1]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   impl_decl @impl.2 {} {
+// CHECK:STDOUT:     %C.ref.loc14_7: type = name_ref C, file.%C.decl [template = constants.%C]
+// CHECK:STDOUT:     %C.ref.loc14_10: type = name_ref C, file.%C.decl [template = constants.%C]
+// CHECK:STDOUT:     %.loc14_11.1: %.4 = tuple_literal (%C.ref.loc14_7, %C.ref.loc14_10)
+// CHECK:STDOUT:     %.loc14_13: i32 = int_literal 0 [template = constants.%.5]
+// CHECK:STDOUT:     %tuple: %.4 = tuple_value (%C.ref.loc14_7, %C.ref.loc14_10) [template = constants.%tuple]
+// CHECK:STDOUT:     %.loc14_11.2: %.4 = converted %.loc14_11.1, %tuple [template = constants.%tuple]
+// CHECK:STDOUT:     %.loc14_12: type = tuple_access %.loc14_11.2, element0 [template = constants.%C]
+// CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [template = constants.%.1]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @I {
+// CHECK:STDOUT:   %Self: %.1 = bind_symbolic_name Self 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   witness = ()
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: impl @impl.1: %C as %.1 {
+// CHECK:STDOUT:   %.loc13: <witness> = interface_witness () [template = constants.%.3]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   witness = %.loc13
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: impl @impl.2: %C as %.1 {
+// CHECK:STDOUT:   %.loc14_20: <witness> = interface_witness () [template = constants.%.3]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   witness = %.loc14_20
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C;
+// CHECK:STDOUT:

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

@@ -0,0 +1,408 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// AUTOUPDATE
+// TIP: To test this file alone, run:
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/impl/no_prelude/import_generic.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/impl/no_prelude/import_generic.carbon
+
+// --- import_generic.carbon
+
+library "[[@TEST_NAME]]";
+
+class C {}
+interface I(T:! type) {}
+
+impl forall [T:! type] C as I(T);
+impl forall [T:! type] C as I(T*) {}
+
+// --- import_generic.impl.carbon
+
+impl library "[[@TEST_NAME]]";
+
+impl forall [T:! type] C as I(T) {}
+
+// --- fail_import_generic.impl.carbon
+
+impl library "[[@TEST_NAME]]";
+
+// CHECK:STDERR: fail_import_generic.impl.carbon:[[@LINE+7]]:1: error: redefinition of `impl C as I`
+// CHECK:STDERR: impl forall [T:! type] C as I(T*) {}
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR: fail_import_generic.impl.carbon:[[@LINE-5]]:6: in import
+// CHECK:STDERR: import_generic.carbon:8:1: note: previous definition was here
+// CHECK:STDERR: impl forall [T:! type] C as I(T*) {}
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+impl forall [T:! type] C as I(T*) {}
+
+// CHECK:STDOUT: --- import_generic.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %.2: <witness> = complete_type_witness %.1 [template]
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T 0 [symbolic]
+// CHECK:STDOUT:   %I.type: type = generic_interface_type @I [template]
+// CHECK:STDOUT:   %.3: type = tuple_type () [template]
+// CHECK:STDOUT:   %I: %I.type = struct_value () [template]
+// CHECK:STDOUT:   %.4: type = interface_type @I, @I(%T) [symbolic]
+// CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 1 [symbolic]
+// CHECK:STDOUT:   %.5: type = ptr_type %T [symbolic]
+// CHECK:STDOUT:   %.6: type = interface_type @I, @I(%.5) [symbolic]
+// CHECK:STDOUT:   %.7: <witness> = interface_witness () [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .I = %I.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {} {}
+// CHECK:STDOUT:   %I.decl: %I.type = interface_decl @I [template = constants.%I] {
+// 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.loc5: type = bind_symbolic_name T 0, %T.param [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   impl_decl @impl.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.loc7: type = bind_symbolic_name T 0, %T.param [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:     %C.ref: type = name_ref C, file.%C.decl [template = constants.%C]
+// CHECK:STDOUT:     %I.ref: %I.type = name_ref I, file.%I.decl [template = constants.%I]
+// CHECK:STDOUT:     %T.ref: type = name_ref T, %T.loc7 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:     %.loc7: type = interface_type @I, @I(constants.%T) [symbolic = %.1 (constants.%.4)]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   impl_decl @impl.2 {
+// 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:     %C.ref: type = name_ref C, file.%C.decl [template = constants.%C]
+// CHECK:STDOUT:     %I.ref: %I.type = name_ref I, file.%I.decl [template = constants.%I]
+// CHECK:STDOUT:     %T.ref: type = name_ref T, %T.loc8 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:     %.loc8_32: type = ptr_type %T [symbolic = %.1 (constants.%.5)]
+// CHECK:STDOUT:     %.loc8_30: type = interface_type @I, @I(constants.%.5) [symbolic = %.2 (constants.%.6)]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic interface @I(%T.loc5: type) {
+// CHECK:STDOUT:   %T.1: type = bind_symbolic_name T 0 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %.1: type = interface_type @I, @I(%T.1) [symbolic = %.1 (constants.%.4)]
+// CHECK:STDOUT:   %Self.2: %.4 = bind_symbolic_name Self 1 [symbolic = %Self.2 (constants.%Self)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   interface {
+// CHECK:STDOUT:     %Self.1: @I.%.1 (%.4) = bind_symbolic_name Self 1 [symbolic = %Self.2 (constants.%Self)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .Self = %Self.1
+// CHECK:STDOUT:     witness = ()
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic impl @impl.1(%T.loc7: type) {
+// CHECK:STDOUT:   %T.1: type = bind_symbolic_name T 0 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:   %.1: type = interface_type @I, @I(%T.1) [symbolic = %.1 (constants.%.4)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   impl: %C as %.4;
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic impl @impl.2(%T.loc8: type) {
+// CHECK:STDOUT:   %T.1: type = bind_symbolic_name T 0 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:   %.1: type = ptr_type @impl.2.%T.1 (%T) [symbolic = %.1 (constants.%.5)]
+// CHECK:STDOUT:   %.2: type = interface_type @I, @I(%.1) [symbolic = %.2 (constants.%.6)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   impl: %C as %.6 {
+// CHECK:STDOUT:     %.loc8_35: <witness> = interface_witness () [template = constants.%.7]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     witness = %.loc8_35
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT:   %.loc4: <witness> = complete_type_witness %.1 [template = constants.%.2]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @I(constants.%T) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @I(@I.%T.1) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @I(@impl.1.%T.1) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl.1(constants.%T) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT:   %.1 => constants.%.4
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @I(constants.%.5) {
+// CHECK:STDOUT:   %T.1 => constants.%.5
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %.1 => constants.%.6
+// CHECK:STDOUT:   %Self.2 => constants.%Self
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @I(@impl.2.%.1) {
+// CHECK:STDOUT:   %T.1 => constants.%.5
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl.2(constants.%T) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT:   %.1 => constants.%.5
+// CHECK:STDOUT:   %.2 => constants.%.6
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- import_generic.impl.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T 0 [symbolic]
+// CHECK:STDOUT:   %I.type: type = generic_interface_type @I [template]
+// CHECK:STDOUT:   %.1: type = tuple_type () [template]
+// CHECK:STDOUT:   %I: %I.type = struct_value () [template]
+// CHECK:STDOUT:   %.2: type = interface_type @I, @I(%T) [symbolic]
+// CHECK:STDOUT:   %Self.1: @I.%.1 (%.2) = bind_symbolic_name Self 1 [symbolic]
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.3: type = struct_type {} [template]
+// CHECK:STDOUT:   %.4: <witness> = complete_type_witness %.3 [template]
+// CHECK:STDOUT:   %Self.2: %.2 = bind_symbolic_name Self 1 [symbolic]
+// CHECK:STDOUT:   %.5: type = ptr_type %T [symbolic]
+// CHECK:STDOUT:   %.6: type = interface_type @I, @I(%.5) [symbolic]
+// CHECK:STDOUT:   %.7: <witness> = interface_witness () [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//import_generic, inst+1, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.2: %I.type = import_ref Main//import_generic, inst+10, loaded [template = constants.%I]
+// CHECK:STDOUT:   %import_ref.3 = import_ref Main//import_generic, inst+16, unloaded
+// CHECK:STDOUT:   %import_ref.4 = import_ref Main//import_generic, inst+2, unloaded
+// CHECK:STDOUT:   %import_ref.5 = import_ref Main//import_generic, inst+44, unloaded
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = imports.%import_ref.1
+// CHECK:STDOUT:     .I = imports.%import_ref.2
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %default.import.loc2_6.1 = import <invalid>
+// CHECK:STDOUT:   %default.import.loc2_6.2 = import <invalid>
+// CHECK:STDOUT:   impl_decl @impl.1 {} {
+// CHECK:STDOUT:     %T.param: type = param T, runtime_param<invalid>
+// CHECK:STDOUT:     %T.loc4: type = bind_symbolic_name T 0, %T.param [symbolic = constants.%T]
+// CHECK:STDOUT:     %C.ref: type = name_ref C, imports.%import_ref.1 [template = constants.%C]
+// CHECK:STDOUT:     %I.ref: %I.type = name_ref I, imports.%import_ref.2 [template = constants.%I]
+// CHECK:STDOUT:     %T.ref: type = name_ref T, %T.loc4 [symbolic = constants.%T]
+// CHECK:STDOUT:     %.loc4_30: type = interface_type @I, @I(constants.%T) [symbolic = constants.%.2]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic interface @I(constants.%T: type) {
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T 0 [symbolic = %T (constants.%T)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %.1: type = interface_type @I, @I(%T) [symbolic = %.1 (constants.%.2)]
+// CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self.2)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   interface {
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .Self = imports.%import_ref.3
+// CHECK:STDOUT:     witness = ()
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic impl @impl.1(constants.%T: type) {
+// CHECK:STDOUT:   %T.1: type = bind_symbolic_name T 0 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:   %.1: type = interface_type @I, @I(%T.1) [symbolic = %.1 (constants.%.2)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   impl: %C as %.2 {
+// CHECK:STDOUT:     %.loc4_34: <witness> = interface_witness () [template = constants.%.7]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     witness = %.loc4_34
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic impl @impl.2(constants.%T: type) {
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T 0 [symbolic = %T (constants.%T)]
+// CHECK:STDOUT:   %.1: type = ptr_type @impl.2.%T (%T) [symbolic = %.1 (constants.%.5)]
+// CHECK:STDOUT:   %.2: type = interface_type @I, @I(%.1) [symbolic = %.2 (constants.%.6)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   impl: %C as %.6 {
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     witness = imports.%import_ref.5
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = imports.%import_ref.4
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @I(constants.%T) {
+// CHECK:STDOUT:   %T => constants.%T
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %.1 => constants.%.2
+// CHECK:STDOUT:   %Self => constants.%Self.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @I(@I.%T) {
+// CHECK:STDOUT:   %T => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @I(@impl.1.%T.1) {
+// CHECK:STDOUT:   %T => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl.1(constants.%T) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT:   %.1 => constants.%.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @I(constants.%.5) {
+// CHECK:STDOUT:   %T => constants.%.5
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %.1 => constants.%.6
+// CHECK:STDOUT:   %Self => constants.%Self.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @I(@impl.2.%.1) {
+// CHECK:STDOUT:   %T => constants.%.5
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl.2(constants.%T) {
+// CHECK:STDOUT:   %T => constants.%T
+// CHECK:STDOUT:   %.1 => constants.%.5
+// CHECK:STDOUT:   %.2 => constants.%.6
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_import_generic.impl.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T 0 [symbolic]
+// CHECK:STDOUT:   %I.type: type = generic_interface_type @I [template]
+// CHECK:STDOUT:   %.1: type = tuple_type () [template]
+// CHECK:STDOUT:   %I: %I.type = struct_value () [template]
+// CHECK:STDOUT:   %.2: type = interface_type @I, @I(%T) [symbolic]
+// CHECK:STDOUT:   %Self.1: @I.%.1 (%.2) = bind_symbolic_name Self 1 [symbolic]
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.3: type = struct_type {} [template]
+// CHECK:STDOUT:   %.4: <witness> = complete_type_witness %.3 [template]
+// CHECK:STDOUT:   %Self.2: %.2 = bind_symbolic_name Self 1 [symbolic]
+// CHECK:STDOUT:   %.5: type = ptr_type %T [symbolic]
+// CHECK:STDOUT:   %.6: type = interface_type @I, @I(%.5) [symbolic]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//import_generic, inst+1, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.2: %I.type = import_ref Main//import_generic, inst+10, loaded [template = constants.%I]
+// CHECK:STDOUT:   %import_ref.3 = import_ref Main//import_generic, inst+16, unloaded
+// CHECK:STDOUT:   %import_ref.4 = import_ref Main//import_generic, inst+2, unloaded
+// CHECK:STDOUT:   %import_ref.5 = import_ref Main//import_generic, inst+44, unloaded
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = imports.%import_ref.1
+// CHECK:STDOUT:     .I = imports.%import_ref.2
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %default.import.loc2_6.1 = import <invalid>
+// CHECK:STDOUT:   %default.import.loc2_6.2 = import <invalid>
+// CHECK:STDOUT:   impl_decl @impl.2 {} {
+// CHECK:STDOUT:     %T.param: type = param T, runtime_param<invalid>
+// CHECK:STDOUT:     %T.loc11: type = bind_symbolic_name T 0, %T.param [symbolic = constants.%T]
+// CHECK:STDOUT:     %C.ref: type = name_ref C, imports.%import_ref.1 [template = constants.%C]
+// CHECK:STDOUT:     %I.ref: %I.type = name_ref I, imports.%import_ref.2 [template = constants.%I]
+// CHECK:STDOUT:     %T.ref: type = name_ref T, %T.loc11 [symbolic = constants.%T]
+// CHECK:STDOUT:     %.loc11_32: type = ptr_type %T [symbolic = constants.%.5]
+// CHECK:STDOUT:     %.loc11_30: type = interface_type @I, @I(constants.%.5) [symbolic = constants.%.6]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic interface @I(constants.%T: type) {
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T 0 [symbolic = %T (constants.%T)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %.1: type = interface_type @I, @I(%T) [symbolic = %.1 (constants.%.2)]
+// CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self.2)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   interface {
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .Self = imports.%import_ref.3
+// CHECK:STDOUT:     witness = ()
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic impl @impl.1(constants.%T: type) {
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T 0 [symbolic = %T (constants.%T)]
+// CHECK:STDOUT:   %.1: type = interface_type @I, @I(%T) [symbolic = %.1 (constants.%.2)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   impl: %C as %.2;
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic impl @impl.2(constants.%T: type) {
+// CHECK:STDOUT:   %T.1: type = bind_symbolic_name T 0 [symbolic = %T.1 (constants.%T)]
+// CHECK:STDOUT:   %.1: type = ptr_type @impl.2.%T.1 (%T) [symbolic = %.1 (constants.%.5)]
+// CHECK:STDOUT:   %.2: type = interface_type @I, @I(%.1) [symbolic = %.2 (constants.%.6)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   impl: %C as %.6 {
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     witness = imports.%import_ref.5
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = imports.%import_ref.4
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @I(constants.%T) {
+// CHECK:STDOUT:   %T => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @I(@I.%T) {
+// CHECK:STDOUT:   %T => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @I(@impl.1.%T) {
+// CHECK:STDOUT:   %T => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl.1(constants.%T) {
+// CHECK:STDOUT:   %T => constants.%T
+// CHECK:STDOUT:   %.1 => constants.%.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @I(constants.%.5) {
+// CHECK:STDOUT:   %T => constants.%.5
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %.1 => constants.%.6
+// CHECK:STDOUT:   %Self => constants.%Self.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @I(@impl.2.%.1) {
+// CHECK:STDOUT:   %T => constants.%.5
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @impl.2(constants.%T) {
+// CHECK:STDOUT:   %T.1 => constants.%T
+// CHECK:STDOUT:   %.1 => constants.%.5
+// CHECK:STDOUT:   %.2 => constants.%.6
+// CHECK:STDOUT: }
+// CHECK:STDOUT:

+ 103 - 95
toolchain/check/testdata/impl/no_prelude/interface_args.carbon

@@ -244,10 +244,9 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT: --- action.impl.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
-// CHECK:STDOUT:   %A: type = class_type @A [template]
+// CHECK:STDOUT:   %B: type = class_type @B [template]
 // CHECK:STDOUT:   %.1: type = struct_type {} [template]
 // CHECK:STDOUT:   %.2: <witness> = complete_type_witness %.1 [template]
-// CHECK:STDOUT:   %B: type = class_type @B [template]
 // CHECK:STDOUT:   %Action.type: type = generic_interface_type @Action [template]
 // CHECK:STDOUT:   %.3: type = tuple_type () [template]
 // CHECK:STDOUT:   %Action: %Action.type = struct_value () [template]
@@ -255,19 +254,20 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %.4: type = interface_type @Action, @Action(%T) [symbolic]
 // CHECK:STDOUT:   %Self.1: @Action.%.1 (%.4) = bind_symbolic_name Self 1 [symbolic]
 // CHECK:STDOUT:   %.5: type = interface_type @Action, @Action(%B) [template]
+// CHECK:STDOUT:   %A: type = class_type @A [template]
 // CHECK:STDOUT:   %Self.2: %.4 = bind_symbolic_name Self 1 [symbolic]
 // CHECK:STDOUT:   %Op.type.1: type = fn_type @Op.1, @Action(%T) [symbolic]
 // CHECK:STDOUT:   %Op.1: %Op.type.1 = struct_value () [symbolic]
 // CHECK:STDOUT:   %.6: type = assoc_entity_type %.4, %Op.type.1 [symbolic]
-// CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, imports.%import_ref.11 [symbolic]
+// CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, imports.%import_ref.13 [symbolic]
 // CHECK:STDOUT:   %Op.type.2: type = fn_type @Op.1, @Action(%B) [template]
 // CHECK:STDOUT:   %Op.2: %Op.type.2 = struct_value () [template]
 // CHECK:STDOUT:   %.8: type = assoc_entity_type %.5, %Op.type.2 [template]
-// CHECK:STDOUT:   %.9: %.8 = assoc_entity element0, imports.%import_ref.12 [template]
+// CHECK:STDOUT:   %.9: %.8 = assoc_entity element0, imports.%import_ref.14 [template]
 // CHECK:STDOUT:   %G.type: type = fn_type @G [template]
 // CHECK:STDOUT:   %G: %G.type = struct_value () [template]
 // CHECK:STDOUT:   %.10: type = ptr_type %.1 [template]
-// CHECK:STDOUT:   %.11: %.6 = assoc_entity element0, imports.%import_ref.14 [symbolic]
+// CHECK:STDOUT:   %.11: %.6 = assoc_entity element0, imports.%import_ref.15 [symbolic]
 // CHECK:STDOUT:   %Op.type.3: type = fn_type @Op.2 [template]
 // CHECK:STDOUT:   %Op.3: %Op.type.3 = struct_value () [template]
 // CHECK:STDOUT:   %.12: <witness> = interface_witness (%Op.3) [template]
@@ -279,15 +279,16 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %import_ref.3: type = import_ref Main//action, inst+30, loaded [template = constants.%B]
 // CHECK:STDOUT:   %import_ref.4 = import_ref Main//action, inst+33, unloaded
 // CHECK:STDOUT:   %import_ref.5 = import_ref Main//action, inst+56, unloaded
-// CHECK:STDOUT:   %import_ref.6 = import_ref Main//action, inst+26, unloaded
-// CHECK:STDOUT:   %import_ref.7 = import_ref Main//action, inst+31, unloaded
-// CHECK:STDOUT:   %import_ref.8 = import_ref Main//action, inst+11, unloaded
-// CHECK:STDOUT:   %import_ref.9: @Action.%.2 (%.6) = import_ref Main//action, inst+17, loaded [symbolic = @Action.%.3 (constants.%.11)]
-// CHECK:STDOUT:   %import_ref.10 = import_ref Main//action, inst+13, unloaded
-// CHECK:STDOUT:   %import_ref.11 = import_ref Main//action, inst+13, unloaded
-// CHECK:STDOUT:   %import_ref.12 = import_ref Main//action, inst+13, unloaded
-// CHECK:STDOUT:   %import_ref.13: <witness> = import_ref Main//action, inst+49, loaded [template = constants.%.12]
+// CHECK:STDOUT:   %import_ref.6 = import_ref Main//action, inst+31, unloaded
+// CHECK:STDOUT:   %import_ref.7 = import_ref Main//action, inst+11, unloaded
+// CHECK:STDOUT:   %import_ref.8: @Action.%.2 (%.6) = import_ref Main//action, inst+17, loaded [symbolic = @Action.%.3 (constants.%.11)]
+// CHECK:STDOUT:   %import_ref.9 = import_ref Main//action, inst+13, unloaded
+// CHECK:STDOUT:   %import_ref.10 = import_ref Main//action, inst+26, unloaded
+// CHECK:STDOUT:   %import_ref.11: <witness> = import_ref Main//action, inst+49, loaded [template = constants.%.12]
+// CHECK:STDOUT:   %import_ref.12 = import_ref Main//action, inst+42, unloaded
+// CHECK:STDOUT:   %import_ref.13 = import_ref Main//action, inst+13, unloaded
 // CHECK:STDOUT:   %import_ref.14 = import_ref Main//action, inst+13, unloaded
+// CHECK:STDOUT:   %import_ref.15 = import_ref Main//action, inst+13, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -319,29 +320,30 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %Op.type: type = fn_type @Op.1, @Action(%T) [symbolic = %Op.type (constants.%Op.type.1)]
 // CHECK:STDOUT:   %Op: @Action.%Op.type (%Op.type.1) = struct_value () [symbolic = %Op (constants.%Op.1)]
 // CHECK:STDOUT:   %.2: type = assoc_entity_type @Action.%.1 (%.4), @Action.%Op.type (%Op.type.1) [symbolic = %.2 (constants.%.6)]
-// CHECK:STDOUT:   %.3: @Action.%.2 (%.6) = assoc_entity element0, imports.%import_ref.11 [symbolic = %.3 (constants.%.7)]
+// CHECK:STDOUT:   %.3: @Action.%.2 (%.6) = assoc_entity element0, imports.%import_ref.13 [symbolic = %.3 (constants.%.7)]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   interface {
 // CHECK:STDOUT:   !members:
-// CHECK:STDOUT:     .Self = imports.%import_ref.8
-// CHECK:STDOUT:     .Op = imports.%import_ref.9
-// CHECK:STDOUT:     witness = (imports.%import_ref.10)
+// CHECK:STDOUT:     .Self = imports.%import_ref.7
+// CHECK:STDOUT:     .Op = imports.%import_ref.8
+// CHECK:STDOUT:     witness = (imports.%import_ref.9)
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: impl @impl: %A as %.5 {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   witness = imports.%import_ref.13
+// CHECK:STDOUT:   .Op = imports.%import_ref.12
+// CHECK:STDOUT:   witness = imports.%import_ref.11
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: class @A {
+// CHECK:STDOUT: class @B {
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = imports.%import_ref.6
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: class @B {
+// CHECK:STDOUT: class @A {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = imports.%import_ref.7
+// CHECK:STDOUT:   .Self = imports.%import_ref.10
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: generic fn @Op.1(constants.%T: type, constants.%Self.1: @Action.%.1 (%.4)) {
@@ -355,9 +357,9 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %Action.ref: %Action.type = name_ref Action, imports.%import_ref.1 [template = constants.%Action]
 // CHECK:STDOUT:   %B.ref: type = name_ref B, imports.%import_ref.3 [template = constants.%B]
 // CHECK:STDOUT:   %.loc4_23: type = interface_type @Action, @Action(constants.%B) [template = constants.%.5]
-// CHECK:STDOUT:   %.loc4_26: %.8 = specific_constant imports.%import_ref.9, @Action(constants.%B) [template = constants.%.9]
+// CHECK:STDOUT:   %.loc4_26: %.8 = specific_constant imports.%import_ref.8, @Action(constants.%B) [template = constants.%.9]
 // CHECK:STDOUT:   %Op.ref: %.8 = name_ref Op, %.loc4_26 [template = constants.%.9]
-// CHECK:STDOUT:   %.loc4_15: %Op.type.2 = interface_witness_access imports.%import_ref.13, element0 [template = constants.%Op.3]
+// CHECK:STDOUT:   %.loc4_15: %Op.type.2 = interface_witness_access imports.%import_ref.11, element0 [template = constants.%Op.3]
 // CHECK:STDOUT:   %Op.call: init %.3 = call %.loc4_15()
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
@@ -389,10 +391,9 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT: --- fail_action.impl.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
-// CHECK:STDOUT:   %A: type = class_type @A [template]
+// CHECK:STDOUT:   %B: type = class_type @B [template]
 // CHECK:STDOUT:   %.1: type = struct_type {} [template]
 // CHECK:STDOUT:   %.2: <witness> = complete_type_witness %.1 [template]
-// CHECK:STDOUT:   %B: type = class_type @B [template]
 // CHECK:STDOUT:   %Action.type: type = generic_interface_type @Action [template]
 // CHECK:STDOUT:   %.3: type = tuple_type () [template]
 // CHECK:STDOUT:   %Action: %Action.type = struct_value () [template]
@@ -400,15 +401,16 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %.4: type = interface_type @Action, @Action(%T) [symbolic]
 // CHECK:STDOUT:   %Self.1: @Action.%.1 (%.4) = bind_symbolic_name Self 1 [symbolic]
 // CHECK:STDOUT:   %.5: type = interface_type @Action, @Action(%B) [template]
+// CHECK:STDOUT:   %A: type = class_type @A [template]
 // CHECK:STDOUT:   %Self.2: %.4 = bind_symbolic_name Self 1 [symbolic]
 // CHECK:STDOUT:   %Op.type.1: type = fn_type @Op, @Action(%T) [symbolic]
 // CHECK:STDOUT:   %Op.1: %Op.type.1 = struct_value () [symbolic]
 // CHECK:STDOUT:   %.6: type = assoc_entity_type %.4, %Op.type.1 [symbolic]
-// CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, imports.%import_ref.11 [symbolic]
+// CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, imports.%import_ref.13 [symbolic]
 // CHECK:STDOUT:   %Op.type.2: type = fn_type @Op, @Action(%B) [template]
 // CHECK:STDOUT:   %Op.2: %Op.type.2 = struct_value () [template]
 // CHECK:STDOUT:   %.8: type = assoc_entity_type %.5, %Op.type.2 [template]
-// CHECK:STDOUT:   %.9: %.8 = assoc_entity element0, imports.%import_ref.12 [template]
+// CHECK:STDOUT:   %.9: %.8 = assoc_entity element0, imports.%import_ref.14 [template]
 // CHECK:STDOUT:   %G.type: type = fn_type @G [template]
 // CHECK:STDOUT:   %G: %G.type = struct_value () [template]
 // CHECK:STDOUT:   %.10: type = ptr_type %.1 [template]
@@ -417,8 +419,8 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %Op.type.3: type = fn_type @Op, @Action(%C) [template]
 // CHECK:STDOUT:   %Op.3: %Op.type.3 = struct_value () [template]
 // CHECK:STDOUT:   %.12: type = assoc_entity_type %.11, %Op.type.3 [template]
-// CHECK:STDOUT:   %.13: %.12 = assoc_entity element0, imports.%import_ref.11 [template]
-// CHECK:STDOUT:   %.14: %.6 = assoc_entity element0, imports.%import_ref.15 [symbolic]
+// CHECK:STDOUT:   %.13: %.12 = assoc_entity element0, imports.%import_ref.13 [template]
+// CHECK:STDOUT:   %.14: %.6 = assoc_entity element0, imports.%import_ref.16 [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -427,16 +429,17 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %import_ref.3 = import_ref Main//action, inst+30, unloaded
 // CHECK:STDOUT:   %import_ref.4: type = import_ref Main//action, inst+33, loaded [template = constants.%C]
 // CHECK:STDOUT:   %import_ref.5 = import_ref Main//action, inst+56, unloaded
-// CHECK:STDOUT:   %import_ref.6 = import_ref Main//action, inst+26, unloaded
-// CHECK:STDOUT:   %import_ref.7 = import_ref Main//action, inst+31, unloaded
-// CHECK:STDOUT:   %import_ref.8 = import_ref Main//action, inst+11, unloaded
-// CHECK:STDOUT:   %import_ref.9: @Action.%.2 (%.6) = import_ref Main//action, inst+17, loaded [symbolic = @Action.%.3 (constants.%.14)]
-// CHECK:STDOUT:   %import_ref.10 = import_ref Main//action, inst+13, unloaded
-// CHECK:STDOUT:   %import_ref.11 = import_ref Main//action, inst+13, unloaded
-// CHECK:STDOUT:   %import_ref.12 = import_ref Main//action, inst+13, unloaded
-// CHECK:STDOUT:   %import_ref.13 = import_ref Main//action, inst+49, unloaded
-// CHECK:STDOUT:   %import_ref.14 = import_ref Main//action, inst+34, unloaded
-// CHECK:STDOUT:   %import_ref.15 = import_ref Main//action, inst+13, unloaded
+// CHECK:STDOUT:   %import_ref.6 = import_ref Main//action, inst+31, unloaded
+// CHECK:STDOUT:   %import_ref.7 = import_ref Main//action, inst+11, unloaded
+// CHECK:STDOUT:   %import_ref.8: @Action.%.2 (%.6) = import_ref Main//action, inst+17, loaded [symbolic = @Action.%.3 (constants.%.14)]
+// CHECK:STDOUT:   %import_ref.9 = import_ref Main//action, inst+13, unloaded
+// CHECK:STDOUT:   %import_ref.10 = import_ref Main//action, inst+26, unloaded
+// CHECK:STDOUT:   %import_ref.11 = import_ref Main//action, inst+49, unloaded
+// CHECK:STDOUT:   %import_ref.12 = import_ref Main//action, inst+42, unloaded
+// CHECK:STDOUT:   %import_ref.13 = import_ref Main//action, inst+13, unloaded
+// CHECK:STDOUT:   %import_ref.14 = import_ref Main//action, inst+13, unloaded
+// CHECK:STDOUT:   %import_ref.15 = import_ref Main//action, inst+34, unloaded
+// CHECK:STDOUT:   %import_ref.16 = import_ref Main//action, inst+13, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -468,34 +471,35 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %Op.type: type = fn_type @Op, @Action(%T) [symbolic = %Op.type (constants.%Op.type.1)]
 // CHECK:STDOUT:   %Op: @Action.%Op.type (%Op.type.1) = struct_value () [symbolic = %Op (constants.%Op.1)]
 // CHECK:STDOUT:   %.2: type = assoc_entity_type @Action.%.1 (%.4), @Action.%Op.type (%Op.type.1) [symbolic = %.2 (constants.%.6)]
-// CHECK:STDOUT:   %.3: @Action.%.2 (%.6) = assoc_entity element0, imports.%import_ref.11 [symbolic = %.3 (constants.%.7)]
+// CHECK:STDOUT:   %.3: @Action.%.2 (%.6) = assoc_entity element0, imports.%import_ref.13 [symbolic = %.3 (constants.%.7)]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   interface {
 // CHECK:STDOUT:   !members:
-// CHECK:STDOUT:     .Self = imports.%import_ref.8
-// CHECK:STDOUT:     .Op = imports.%import_ref.9
-// CHECK:STDOUT:     witness = (imports.%import_ref.10)
+// CHECK:STDOUT:     .Self = imports.%import_ref.7
+// CHECK:STDOUT:     .Op = imports.%import_ref.8
+// CHECK:STDOUT:     witness = (imports.%import_ref.9)
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: impl @impl: %A as %.5 {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   witness = imports.%import_ref.13
+// CHECK:STDOUT:   .Op = imports.%import_ref.12
+// CHECK:STDOUT:   witness = imports.%import_ref.11
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: class @A {
+// CHECK:STDOUT: class @B {
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = imports.%import_ref.6
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: class @B {
+// CHECK:STDOUT: class @A {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = imports.%import_ref.7
+// CHECK:STDOUT:   .Self = imports.%import_ref.10
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = imports.%import_ref.14
+// CHECK:STDOUT:   .Self = imports.%import_ref.15
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: generic fn @Op(constants.%T: type, constants.%Self.1: @Action.%.1 (%.4)) {
@@ -509,7 +513,7 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %Action.ref: %Action.type = name_ref Action, imports.%import_ref.1 [template = constants.%Action]
 // CHECK:STDOUT:   %C.ref: type = name_ref C, imports.%import_ref.4 [template = constants.%C]
 // CHECK:STDOUT:   %.loc8_23: type = interface_type @Action, @Action(constants.%C) [template = constants.%.11]
-// CHECK:STDOUT:   %.loc8_26: %.12 = specific_constant imports.%import_ref.9, @Action(constants.%C) [template = constants.%.13]
+// CHECK:STDOUT:   %.loc8_26: %.12 = specific_constant imports.%import_ref.8, @Action(constants.%C) [template = constants.%.13]
 // CHECK:STDOUT:   %Op.ref: %.12 = name_ref Op, %.loc8_26 [template = constants.%.13]
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
@@ -688,10 +692,9 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT: --- factory.impl.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
-// CHECK:STDOUT:   %A: type = class_type @A [template]
+// CHECK:STDOUT:   %B: type = class_type @B [template]
 // CHECK:STDOUT:   %.1: type = struct_type {} [template]
 // CHECK:STDOUT:   %.2: <witness> = complete_type_witness %.1 [template]
-// CHECK:STDOUT:   %B: type = class_type @B [template]
 // CHECK:STDOUT:   %Factory.type: type = generic_interface_type @Factory [template]
 // CHECK:STDOUT:   %.3: type = tuple_type () [template]
 // CHECK:STDOUT:   %Factory: %Factory.type = struct_value () [template]
@@ -699,19 +702,20 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %.4: type = interface_type @Factory, @Factory(%T) [symbolic]
 // CHECK:STDOUT:   %Self.1: @Factory.%.1 (%.4) = bind_symbolic_name Self 1 [symbolic]
 // CHECK:STDOUT:   %.5: type = interface_type @Factory, @Factory(%B) [template]
+// CHECK:STDOUT:   %A: type = class_type @A [template]
 // CHECK:STDOUT:   %Self.2: %.4 = bind_symbolic_name Self 1 [symbolic]
 // CHECK:STDOUT:   %Make.type.1: type = fn_type @Make.1, @Factory(%T) [symbolic]
 // CHECK:STDOUT:   %Make.1: %Make.type.1 = struct_value () [symbolic]
 // CHECK:STDOUT:   %.6: type = assoc_entity_type %.4, %Make.type.1 [symbolic]
-// CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, imports.%import_ref.9 [symbolic]
+// CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, imports.%import_ref.11 [symbolic]
 // CHECK:STDOUT:   %Make.type.2: type = fn_type @Make.1, @Factory(%B) [template]
 // CHECK:STDOUT:   %Make.2: %Make.type.2 = struct_value () [template]
 // CHECK:STDOUT:   %.8: type = assoc_entity_type %.5, %Make.type.2 [template]
-// CHECK:STDOUT:   %.9: %.8 = assoc_entity element0, imports.%import_ref.10 [template]
+// CHECK:STDOUT:   %.9: %.8 = assoc_entity element0, imports.%import_ref.12 [template]
 // CHECK:STDOUT:   %MakeB.type: type = fn_type @MakeB [template]
 // CHECK:STDOUT:   %MakeB: %MakeB.type = struct_value () [template]
 // CHECK:STDOUT:   %.10: type = ptr_type %.1 [template]
-// CHECK:STDOUT:   %.11: %.6 = assoc_entity element0, imports.%import_ref.12 [symbolic]
+// CHECK:STDOUT:   %.11: %.6 = assoc_entity element0, imports.%import_ref.13 [symbolic]
 // CHECK:STDOUT:   %Make.type.3: type = fn_type @Make.2 [template]
 // CHECK:STDOUT:   %Make.3: %Make.type.3 = struct_value () [template]
 // CHECK:STDOUT:   %.12: <witness> = interface_witness (%Make.3) [template]
@@ -721,15 +725,16 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %import_ref.1: %Factory.type = import_ref Main//factory, inst+5, loaded [template = constants.%Factory]
 // CHECK:STDOUT:   %import_ref.2: type = import_ref Main//factory, inst+28, loaded [template = constants.%A]
 // CHECK:STDOUT:   %import_ref.3: type = import_ref Main//factory, inst+33, loaded [template = constants.%B]
-// CHECK:STDOUT:   %import_ref.4 = import_ref Main//factory, inst+29, unloaded
-// CHECK:STDOUT:   %import_ref.5 = import_ref Main//factory, inst+34, unloaded
-// CHECK:STDOUT:   %import_ref.6 = import_ref Main//factory, inst+11, unloaded
-// CHECK:STDOUT:   %import_ref.7: @Factory.%.2 (%.6) = import_ref Main//factory, inst+20, loaded [symbolic = @Factory.%.3 (constants.%.11)]
-// CHECK:STDOUT:   %import_ref.8 = import_ref Main//factory, inst+15, unloaded
-// CHECK:STDOUT:   %import_ref.9 = import_ref Main//factory, inst+15, unloaded
-// CHECK:STDOUT:   %import_ref.10 = import_ref Main//factory, inst+15, unloaded
-// CHECK:STDOUT:   %import_ref.11: <witness> = import_ref Main//factory, inst+51, loaded [template = constants.%.12]
+// CHECK:STDOUT:   %import_ref.4 = import_ref Main//factory, inst+34, unloaded
+// CHECK:STDOUT:   %import_ref.5 = import_ref Main//factory, inst+11, unloaded
+// CHECK:STDOUT:   %import_ref.6: @Factory.%.2 (%.6) = import_ref Main//factory, inst+20, loaded [symbolic = @Factory.%.3 (constants.%.11)]
+// CHECK:STDOUT:   %import_ref.7 = import_ref Main//factory, inst+15, unloaded
+// CHECK:STDOUT:   %import_ref.8 = import_ref Main//factory, inst+29, unloaded
+// CHECK:STDOUT:   %import_ref.9: <witness> = import_ref Main//factory, inst+51, loaded [template = constants.%.12]
+// CHECK:STDOUT:   %import_ref.10 = import_ref Main//factory, inst+44, unloaded
+// CHECK:STDOUT:   %import_ref.11 = import_ref Main//factory, inst+15, unloaded
 // CHECK:STDOUT:   %import_ref.12 = import_ref Main//factory, inst+15, unloaded
+// CHECK:STDOUT:   %import_ref.13 = import_ref Main//factory, inst+15, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -761,29 +766,30 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %Make.type: type = fn_type @Make.1, @Factory(%T) [symbolic = %Make.type (constants.%Make.type.1)]
 // CHECK:STDOUT:   %Make: @Factory.%Make.type (%Make.type.1) = struct_value () [symbolic = %Make (constants.%Make.1)]
 // CHECK:STDOUT:   %.2: type = assoc_entity_type @Factory.%.1 (%.4), @Factory.%Make.type (%Make.type.1) [symbolic = %.2 (constants.%.6)]
-// CHECK:STDOUT:   %.3: @Factory.%.2 (%.6) = assoc_entity element0, imports.%import_ref.9 [symbolic = %.3 (constants.%.7)]
+// CHECK:STDOUT:   %.3: @Factory.%.2 (%.6) = assoc_entity element0, imports.%import_ref.11 [symbolic = %.3 (constants.%.7)]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   interface {
 // CHECK:STDOUT:   !members:
-// CHECK:STDOUT:     .Self = imports.%import_ref.6
-// CHECK:STDOUT:     .Make = imports.%import_ref.7
-// CHECK:STDOUT:     witness = (imports.%import_ref.8)
+// CHECK:STDOUT:     .Self = imports.%import_ref.5
+// CHECK:STDOUT:     .Make = imports.%import_ref.6
+// CHECK:STDOUT:     witness = (imports.%import_ref.7)
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: impl @impl: %A as %.5 {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   witness = imports.%import_ref.11
+// CHECK:STDOUT:   .Make = imports.%import_ref.10
+// CHECK:STDOUT:   witness = imports.%import_ref.9
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: class @A {
+// CHECK:STDOUT: class @B {
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = imports.%import_ref.4
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: class @B {
+// CHECK:STDOUT: class @A {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = imports.%import_ref.5
+// CHECK:STDOUT:   .Self = imports.%import_ref.8
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: generic fn @Make.1(constants.%T: type, constants.%Self.1: @Factory.%.1 (%.4)) {
@@ -798,9 +804,9 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %Factory.ref: %Factory.type = name_ref Factory, imports.%import_ref.1 [template = constants.%Factory]
 // CHECK:STDOUT:   %B.ref.loc5: type = name_ref B, imports.%import_ref.3 [template = constants.%B]
 // CHECK:STDOUT:   %.loc5_20: type = interface_type @Factory, @Factory(constants.%B) [template = constants.%.5]
-// CHECK:STDOUT:   %.loc5_23: %.8 = specific_constant imports.%import_ref.7, @Factory(constants.%B) [template = constants.%.9]
+// CHECK:STDOUT:   %.loc5_23: %.8 = specific_constant imports.%import_ref.6, @Factory(constants.%B) [template = constants.%.9]
 // CHECK:STDOUT:   %Make.ref: %.8 = name_ref Make, %.loc5_23 [template = constants.%.9]
-// CHECK:STDOUT:   %.loc5_11: %Make.type.2 = interface_witness_access imports.%import_ref.11, element0 [template = constants.%Make.3]
+// CHECK:STDOUT:   %.loc5_11: %Make.type.2 = interface_witness_access imports.%import_ref.9, element0 [template = constants.%Make.3]
 // CHECK:STDOUT:   %.loc4: ref %B = splice_block %return {}
 // CHECK:STDOUT:   %Make.call: init %B = call %.loc5_11() to %.loc4
 // CHECK:STDOUT:   return %Make.call to %return
@@ -835,10 +841,9 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT: --- fail_factory.impl.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
-// CHECK:STDOUT:   %A: type = class_type @A [template]
+// CHECK:STDOUT:   %B: type = class_type @B [template]
 // CHECK:STDOUT:   %.1: type = struct_type {} [template]
 // CHECK:STDOUT:   %.2: <witness> = complete_type_witness %.1 [template]
-// CHECK:STDOUT:   %B: type = class_type @B [template]
 // CHECK:STDOUT:   %Factory.type: type = generic_interface_type @Factory [template]
 // CHECK:STDOUT:   %.3: type = tuple_type () [template]
 // CHECK:STDOUT:   %Factory: %Factory.type = struct_value () [template]
@@ -846,15 +851,16 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %.4: type = interface_type @Factory, @Factory(%T) [symbolic]
 // CHECK:STDOUT:   %Self.1: @Factory.%.1 (%.4) = bind_symbolic_name Self 1 [symbolic]
 // CHECK:STDOUT:   %.5: type = interface_type @Factory, @Factory(%B) [template]
+// CHECK:STDOUT:   %A: type = class_type @A [template]
 // CHECK:STDOUT:   %Self.2: %.4 = bind_symbolic_name Self 1 [symbolic]
 // CHECK:STDOUT:   %Make.type.1: type = fn_type @Make, @Factory(%T) [symbolic]
 // CHECK:STDOUT:   %Make.1: %Make.type.1 = struct_value () [symbolic]
 // CHECK:STDOUT:   %.6: type = assoc_entity_type %.4, %Make.type.1 [symbolic]
-// CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, imports.%import_ref.9 [symbolic]
+// CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, imports.%import_ref.11 [symbolic]
 // CHECK:STDOUT:   %Make.type.2: type = fn_type @Make, @Factory(%B) [template]
 // CHECK:STDOUT:   %Make.2: %Make.type.2 = struct_value () [template]
 // CHECK:STDOUT:   %.8: type = assoc_entity_type %.5, %Make.type.2 [template]
-// CHECK:STDOUT:   %.9: %.8 = assoc_entity element0, imports.%import_ref.10 [template]
+// CHECK:STDOUT:   %.9: %.8 = assoc_entity element0, imports.%import_ref.12 [template]
 // CHECK:STDOUT:   %C: type = class_type @C [template]
 // CHECK:STDOUT:   %MakeC.type: type = fn_type @MakeC [template]
 // CHECK:STDOUT:   %MakeC: %MakeC.type = struct_value () [template]
@@ -863,23 +869,24 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %Make.type.3: type = fn_type @Make, @Factory(%C) [template]
 // CHECK:STDOUT:   %Make.3: %Make.type.3 = struct_value () [template]
 // CHECK:STDOUT:   %.12: type = assoc_entity_type %.11, %Make.type.3 [template]
-// CHECK:STDOUT:   %.13: %.12 = assoc_entity element0, imports.%import_ref.9 [template]
-// CHECK:STDOUT:   %.14: %.6 = assoc_entity element0, imports.%import_ref.12 [symbolic]
+// CHECK:STDOUT:   %.13: %.12 = assoc_entity element0, imports.%import_ref.11 [template]
+// CHECK:STDOUT:   %.14: %.6 = assoc_entity element0, imports.%import_ref.13 [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %import_ref.1: %Factory.type = import_ref Main//factory, inst+5, loaded [template = constants.%Factory]
 // CHECK:STDOUT:   %import_ref.2: type = import_ref Main//factory, inst+28, loaded [template = constants.%A]
 // CHECK:STDOUT:   %import_ref.3 = import_ref Main//factory, inst+33, unloaded
-// CHECK:STDOUT:   %import_ref.4 = import_ref Main//factory, inst+29, unloaded
-// CHECK:STDOUT:   %import_ref.5 = import_ref Main//factory, inst+34, unloaded
-// CHECK:STDOUT:   %import_ref.6 = import_ref Main//factory, inst+11, unloaded
-// CHECK:STDOUT:   %import_ref.7: @Factory.%.2 (%.6) = import_ref Main//factory, inst+20, loaded [symbolic = @Factory.%.3 (constants.%.14)]
-// CHECK:STDOUT:   %import_ref.8 = import_ref Main//factory, inst+15, unloaded
-// CHECK:STDOUT:   %import_ref.9 = import_ref Main//factory, inst+15, unloaded
-// CHECK:STDOUT:   %import_ref.10 = import_ref Main//factory, inst+15, unloaded
-// CHECK:STDOUT:   %import_ref.11 = import_ref Main//factory, inst+51, unloaded
+// CHECK:STDOUT:   %import_ref.4 = import_ref Main//factory, inst+34, unloaded
+// CHECK:STDOUT:   %import_ref.5 = import_ref Main//factory, inst+11, unloaded
+// CHECK:STDOUT:   %import_ref.6: @Factory.%.2 (%.6) = import_ref Main//factory, inst+20, loaded [symbolic = @Factory.%.3 (constants.%.14)]
+// CHECK:STDOUT:   %import_ref.7 = import_ref Main//factory, inst+15, unloaded
+// CHECK:STDOUT:   %import_ref.8 = import_ref Main//factory, inst+29, unloaded
+// CHECK:STDOUT:   %import_ref.9 = import_ref Main//factory, inst+51, unloaded
+// CHECK:STDOUT:   %import_ref.10 = import_ref Main//factory, inst+44, unloaded
+// CHECK:STDOUT:   %import_ref.11 = import_ref Main//factory, inst+15, unloaded
 // CHECK:STDOUT:   %import_ref.12 = import_ref Main//factory, inst+15, unloaded
+// CHECK:STDOUT:   %import_ref.13 = import_ref Main//factory, inst+15, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -913,29 +920,30 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %Make.type: type = fn_type @Make, @Factory(%T) [symbolic = %Make.type (constants.%Make.type.1)]
 // CHECK:STDOUT:   %Make: @Factory.%Make.type (%Make.type.1) = struct_value () [symbolic = %Make (constants.%Make.1)]
 // CHECK:STDOUT:   %.2: type = assoc_entity_type @Factory.%.1 (%.4), @Factory.%Make.type (%Make.type.1) [symbolic = %.2 (constants.%.6)]
-// CHECK:STDOUT:   %.3: @Factory.%.2 (%.6) = assoc_entity element0, imports.%import_ref.9 [symbolic = %.3 (constants.%.7)]
+// CHECK:STDOUT:   %.3: @Factory.%.2 (%.6) = assoc_entity element0, imports.%import_ref.11 [symbolic = %.3 (constants.%.7)]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   interface {
 // CHECK:STDOUT:   !members:
-// CHECK:STDOUT:     .Self = imports.%import_ref.6
-// CHECK:STDOUT:     .Make = imports.%import_ref.7
-// CHECK:STDOUT:     witness = (imports.%import_ref.8)
+// CHECK:STDOUT:     .Self = imports.%import_ref.5
+// CHECK:STDOUT:     .Make = imports.%import_ref.6
+// CHECK:STDOUT:     witness = (imports.%import_ref.7)
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: impl @impl: %A as %.5 {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   witness = imports.%import_ref.11
+// CHECK:STDOUT:   .Make = imports.%import_ref.10
+// CHECK:STDOUT:   witness = imports.%import_ref.9
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: class @A {
+// CHECK:STDOUT: class @B {
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = imports.%import_ref.4
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: class @B {
+// CHECK:STDOUT: class @A {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = imports.%import_ref.5
+// CHECK:STDOUT:   .Self = imports.%import_ref.8
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
@@ -957,7 +965,7 @@ fn MakeC(a: A) -> C {
 // CHECK:STDOUT:   %Factory.ref: %Factory.type = name_ref Factory, imports.%import_ref.1 [template = constants.%Factory]
 // CHECK:STDOUT:   %C.ref.loc10: type = name_ref C, file.%C.decl [template = constants.%C]
 // CHECK:STDOUT:   %.loc10_20: type = interface_type @Factory, @Factory(constants.%C) [template = constants.%.11]
-// CHECK:STDOUT:   %.loc10_23: %.12 = specific_constant imports.%import_ref.7, @Factory(constants.%C) [template = constants.%.13]
+// CHECK:STDOUT:   %.loc10_23: %.12 = specific_constant imports.%import_ref.6, @Factory(constants.%C) [template = constants.%.13]
 // CHECK:STDOUT:   %Make.ref: %.12 = name_ref Make, %.loc10_23 [template = constants.%.13]
 // CHECK:STDOUT:   return <error> to %return
 // CHECK:STDOUT: }

+ 27 - 27
toolchain/check/testdata/impl/no_prelude/no_definition_in_impl_file.carbon

@@ -112,14 +112,14 @@ impl () as D;
 // CHECK:STDOUT: --- decl_in_api_definition_in_impl.impl.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
-// CHECK:STDOUT:   %.1: type = tuple_type () [template]
-// CHECK:STDOUT:   %.2: type = interface_type @A [template]
-// CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT:   %.1: type = interface_type @A [template]
+// CHECK:STDOUT:   %Self: %.1 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
 // CHECK:STDOUT:   %.3: <witness> = interface_witness () [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//decl_in_api_definition_in_impl, inst+1, loaded [template = constants.%.2]
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//decl_in_api_definition_in_impl, inst+1, loaded [template = constants.%.1]
 // CHECK:STDOUT:   %import_ref.2 = import_ref Main//decl_in_api_definition_in_impl, inst+3, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -130,14 +130,14 @@ impl () as D;
 // CHECK:STDOUT:   %default.import.loc2_6.1 = import <invalid>
 // CHECK:STDOUT:   %default.import.loc2_6.2 = import <invalid>
 // CHECK:STDOUT:   impl_decl @impl {} {
-// CHECK:STDOUT:     %.loc4_7.1: %.1 = tuple_literal ()
-// CHECK:STDOUT:     %.loc4_7.2: type = converted %.loc4_7.1, constants.%.1 [template = constants.%.1]
-// CHECK:STDOUT:     %A.ref.loc4: type = name_ref A, imports.%import_ref.1 [template = constants.%.2]
+// CHECK:STDOUT:     %.loc4_7.1: %.2 = tuple_literal ()
+// CHECK:STDOUT:     %.loc4_7.2: type = converted %.loc4_7.1, constants.%.2 [template = constants.%.2]
+// CHECK:STDOUT:     %A.ref.loc4: type = name_ref A, imports.%import_ref.1 [template = constants.%.1]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   impl_decl @impl {} {
-// CHECK:STDOUT:     %.loc6_7.1: %.1 = tuple_literal ()
-// CHECK:STDOUT:     %.loc6_7.2: type = converted %.loc6_7.1, constants.%.1 [template = constants.%.1]
-// CHECK:STDOUT:     %A.ref.loc6: type = name_ref A, imports.%import_ref.1 [template = constants.%.2]
+// CHECK:STDOUT:     %.loc6_7.1: %.2 = tuple_literal ()
+// CHECK:STDOUT:     %.loc6_7.2: type = converted %.loc6_7.1, constants.%.2 [template = constants.%.2]
+// CHECK:STDOUT:     %A.ref.loc6: type = name_ref A, imports.%import_ref.1 [template = constants.%.1]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -147,7 +147,7 @@ impl () as D;
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %.1 as %.2 {
+// CHECK:STDOUT: impl @impl: %.2 as %.1 {
 // CHECK:STDOUT:   %.loc6_14: <witness> = interface_witness () [template = constants.%.3]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
@@ -163,9 +163,9 @@ impl () as D;
 // CHECK:STDOUT: --- use_decl_in_api.impl.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
-// CHECK:STDOUT:   %.1: type = tuple_type () [template]
-// CHECK:STDOUT:   %.2: type = interface_type @A [template]
-// CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT:   %.1: type = interface_type @A [template]
+// CHECK:STDOUT:   %Self: %.1 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -187,7 +187,7 @@ impl () as D;
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %.1 as %.2;
+// CHECK:STDOUT: impl @impl: %.2 as %.1;
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- decl_only_in_api.carbon
 // CHECK:STDOUT:
@@ -222,9 +222,9 @@ impl () as D;
 // CHECK:STDOUT: --- decl_only_in_api.impl.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
-// CHECK:STDOUT:   %.1: type = tuple_type () [template]
-// CHECK:STDOUT:   %.2: type = interface_type @B [template]
-// CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT:   %.1: type = interface_type @B [template]
+// CHECK:STDOUT:   %Self: %.1 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -246,7 +246,7 @@ impl () as D;
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %.1 as %.2;
+// CHECK:STDOUT: impl @impl: %.2 as %.1;
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- decl_in_api_decl_in_impl.carbon
 // CHECK:STDOUT:
@@ -281,13 +281,13 @@ impl () as D;
 // CHECK:STDOUT: --- fail_decl_in_api_decl_in_impl.impl.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
-// CHECK:STDOUT:   %.1: type = tuple_type () [template]
-// CHECK:STDOUT:   %.2: type = interface_type @C [template]
-// CHECK:STDOUT:   %Self: %.2 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT:   %.1: type = interface_type @C [template]
+// CHECK:STDOUT:   %Self: %.1 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//decl_in_api_decl_in_impl, inst+1, loaded [template = constants.%.2]
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//decl_in_api_decl_in_impl, inst+1, loaded [template = constants.%.1]
 // CHECK:STDOUT:   %import_ref.2 = import_ref Main//decl_in_api_decl_in_impl, inst+3, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -298,9 +298,9 @@ impl () as D;
 // CHECK:STDOUT:   %default.import.loc2_6.1 = import <invalid>
 // CHECK:STDOUT:   %default.import.loc2_6.2 = import <invalid>
 // CHECK:STDOUT:   impl_decl @impl {} {
-// CHECK:STDOUT:     %.loc8_7.1: %.1 = tuple_literal ()
-// CHECK:STDOUT:     %.loc8_7.2: type = converted %.loc8_7.1, constants.%.1 [template = constants.%.1]
-// CHECK:STDOUT:     %C.ref: type = name_ref C, imports.%import_ref.1 [template = constants.%.2]
+// CHECK:STDOUT:     %.loc8_7.1: %.2 = tuple_literal ()
+// CHECK:STDOUT:     %.loc8_7.2: type = converted %.loc8_7.1, constants.%.2 [template = constants.%.2]
+// CHECK:STDOUT:     %C.ref: type = name_ref C, imports.%import_ref.1 [template = constants.%.1]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -310,7 +310,7 @@ impl () as D;
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %.1 as %.2;
+// CHECK:STDOUT: impl @impl: %.2 as %.1;
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- decl_only_in_impl.carbon
 // CHECK:STDOUT:

+ 10 - 8
toolchain/check/testdata/impl/redeclaration.carbon

@@ -55,18 +55,18 @@ impl i32 as I {}
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Core.import = import Core
 // CHECK:STDOUT:   %I.decl: type = interface_decl @I [template = constants.%.1] {} {}
-// CHECK:STDOUT:   impl_decl @impl {} {
+// CHECK:STDOUT:   impl_decl @impl.1 {} {
 // CHECK:STDOUT:     %int.make_type_32.loc13: init type = call constants.%Int32() [template = i32]
 // CHECK:STDOUT:     %.loc13_6.1: type = value_of_initializer %int.make_type_32.loc13 [template = i32]
 // CHECK:STDOUT:     %.loc13_6.2: type = converted %int.make_type_32.loc13, %.loc13_6.1 [template = i32]
 // CHECK:STDOUT:     %I.ref.loc13: type = name_ref I, file.%I.decl [template = constants.%.1]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %X.decl: type = class_decl @X [template = constants.%X] {} {}
-// CHECK:STDOUT:   impl_decl @impl {} {
-// CHECK:STDOUT:     %int.make_type_32.loc19: init type = call constants.%Int32() [template = i32]
-// CHECK:STDOUT:     %.loc19_6.1: type = value_of_initializer %int.make_type_32.loc19 [template = i32]
-// CHECK:STDOUT:     %.loc19_6.2: type = converted %int.make_type_32.loc19, %.loc19_6.1 [template = i32]
-// CHECK:STDOUT:     %I.ref.loc19: type = name_ref I, file.%I.decl [template = constants.%.1]
+// CHECK:STDOUT:   impl_decl @impl.2 {} {
+// CHECK:STDOUT:     %int.make_type_32: init type = call constants.%Int32() [template = i32]
+// CHECK:STDOUT:     %.loc19_6.1: type = value_of_initializer %int.make_type_32 [template = i32]
+// CHECK:STDOUT:     %.loc19_6.2: type = converted %int.make_type_32, %.loc19_6.1 [template = i32]
+// CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [template = constants.%.1]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -78,7 +78,9 @@ impl i32 as I {}
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: i32 as %.1 {
+// CHECK:STDOUT: impl @impl.1: i32 as %.1;
+// CHECK:STDOUT:
+// CHECK:STDOUT: impl @impl.2: i32 as %.1 {
 // CHECK:STDOUT:   %.loc19_15: <witness> = interface_witness () [template = constants.%.5]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
@@ -86,7 +88,7 @@ impl i32 as I {}
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @X {
-// CHECK:STDOUT:   impl_decl @impl {} {
+// CHECK:STDOUT:   impl_decl @impl.1 {} {
 // CHECK:STDOUT:     %int.make_type_32.loc16: init type = call constants.%Int32() [template = i32]
 // CHECK:STDOUT:     %.loc16_8.1: type = value_of_initializer %int.make_type_32.loc16 [template = i32]
 // CHECK:STDOUT:     %.loc16_8.2: type = converted %int.make_type_32.loc16, %.loc16_8.1 [template = i32]

+ 3 - 3
toolchain/check/testdata/interface/no_prelude/import_interface_decl.carbon

@@ -43,8 +43,8 @@ impl library "[[@TEST_NAME]]";
 // CHECK:STDOUT: --- a.impl.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
-// CHECK:STDOUT:   %.1: type = tuple_type () [template]
-// CHECK:STDOUT:   %.2: type = interface_type @A [template]
+// CHECK:STDOUT:   %.1: type = interface_type @A [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -61,5 +61,5 @@ impl library "[[@TEST_NAME]]";
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @A;
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %.1 as %.2;
+// CHECK:STDOUT: impl @impl: %.2 as %.1;
 // CHECK:STDOUT:

+ 3 - 2
toolchain/sem_ir/formatter.cpp

@@ -223,10 +223,9 @@ class FormatterImpl {
   // Formats a full impl.
   auto FormatImpl(ImplId id) -> void {
     const Impl& impl_info = sem_ir_.impls().Get(id);
-    FormatEntityStart("impl", SemIR::GenericId::Invalid, id);
+    FormatEntityStart("impl", impl_info.generic_id, id);
 
     out_ << ": ";
-    // TODO: Include the deduced parameter list if present.
     FormatType(impl_info.self_id);
     out_ << " as ";
     FormatType(impl_info.constraint_id);
@@ -256,6 +255,8 @@ class FormatterImpl {
     } else {
       out_ << ";\n";
     }
+
+    FormatEntityEnd(impl_info.generic_id);
   }
 
   // Formats a full function.

+ 41 - 30
toolchain/sem_ir/impl.h

@@ -6,32 +6,16 @@
 #define CARBON_TOOLCHAIN_SEM_IR_IMPL_H_
 
 #include "common/map.h"
+#include "llvm/ADT/TinyPtrVector.h"
+#include "toolchain/sem_ir/entity_with_params_base.h"
 #include "toolchain/sem_ir/ids.h"
 
 namespace Carbon::SemIR {
 
-// An implementation of a constraint.
-struct Impl : public Printable<Impl> {
-  auto Print(llvm::raw_ostream& out) const -> void {
-    out << "{self: " << self_id << ", constraint: " << constraint_id << "}";
-  }
-
-  // Determines whether this impl has been fully defined. This is false until we
-  // reach the `}` of the impl definition.
-  auto is_defined() const -> bool { return witness_id.is_valid(); }
-
-  // Determines whether this impl's definition has begun but not yet ended.
-  auto is_being_defined() const -> bool {
-    return definition_id.is_valid() && !is_defined();
-  }
-
+struct ImplFields {
   // The following members always have values, and do not change throughout the
   // lifetime of the interface.
 
-  // A block containing the pattern insts for the `impl forall` parameters,
-  // if any.
-  InstBlockId pattern_block_id = InstBlockId::Invalid;
-  // TODO: Track the generic parameters for `impl forall`.
   // The type for which the impl is implementing a constraint.
   TypeId self_id;
   // The constraint that the impl implements.
@@ -39,8 +23,6 @@ struct Impl : public Printable<Impl> {
 
   // The following members are set at the `{` of the impl definition.
 
-  // The definition of the impl. This is an ImplDecl.
-  InstId definition_id = InstId::Invalid;
   // The impl scope.
   NameScopeId scope_id = NameScopeId::Invalid;
   // The first block of the impl body.
@@ -53,20 +35,49 @@ struct Impl : public Printable<Impl> {
   InstId witness_id = InstId::Invalid;
 };
 
+// An implementation of a constraint. See EntityWithParamsBase regarding the
+// inheritance here.
+struct Impl : public EntityWithParamsBase,
+              public ImplFields,
+              public Printable<Impl> {
+  auto Print(llvm::raw_ostream& out) const -> void {
+    out << "{self: " << self_id << ", constraint: " << constraint_id << "}";
+  }
+
+  // Determines whether this impl has been fully defined. This is false until we
+  // reach the `}` of the impl definition.
+  auto is_defined() const -> bool { return witness_id.is_valid(); }
+
+  // Determines whether this impl's definition has begun but not yet ended.
+  auto is_being_defined() const -> bool {
+    return definition_id.is_valid() && !is_defined();
+  }
+};
+
 // A collection of `Impl`s, which can be accessed by the self type and
 // constraint implemented.
 class ImplStore {
  public:
-  // Looks up the impl with this self type and constraint, or creates a new
-  // `Impl` if none exists.
-  // TODO: Handle parameters.
-  auto LookupOrAdd(TypeId self_id, TypeId constraint_id) -> ImplId {
-    auto result = lookup_.Insert(std::pair{self_id, constraint_id}, [&]() {
-      return values_.Add({.self_id = self_id, .constraint_id = constraint_id});
-    });
-    return result.value();
+  // TODO: Switch to something like TinyPtrVector. We expect it to be rare for
+  // there to be more than one ImplId per bucket.
+  using LookupBucket = llvm::SmallVector<ImplId, 1>;
+
+  // Returns the lookup bucket containing the list of impls with this self type
+  // and constraint, or adds a new bucket if this is the first time we've seen
+  // an impl of this kind. The lookup bucket should only include impls from the
+  // current file and its API file; impls from other files should not be added
+  // to it.
+  auto GetOrAddLookupBucket(TypeId self_id, TypeId constraint_id)
+      -> LookupBucket& {
+    return lookup_
+        .Insert(std::pair{self_id, constraint_id},
+                [] { return LookupBucket(); })
+        .value();
   }
 
+  // Adds the specified impl to the store. Does not add it to impl lookup.
+  auto Add(Impl impl) -> ImplId { return values_.Add(impl); }
+
   // Returns a mutable value for an ID.
   auto Get(ImplId id) -> Impl& { return values_.Get(id); }
 
@@ -89,7 +100,7 @@ class ImplStore {
 
  private:
   ValueStore<ImplId> values_;
-  Map<std::pair<TypeId, TypeId>, ImplId> lookup_;
+  Map<std::pair<TypeId, TypeId>, LookupBucket> lookup_;
 };
 
 }  // namespace Carbon::SemIR

+ 1 - 1
toolchain/sem_ir/inst_namer.cpp

@@ -107,7 +107,7 @@ InstNamer::InstNamer(const Lex::TokenizedBuffer& tokenized_buffer,
         globals_.AllocateName(*this, impl_loc, "impl");
     AddBlockLabel(impl_scope, impl_info.body_block_id, "impl", impl_loc);
     CollectNamesInBlock(impl_scope, impl_info.body_block_id);
-    // TODO: Collect names from the generic once we support generic impls.
+    CollectNamesInGeneric(impl_scope, impl_info.generic_id);
   }
 }