Bläddra i källkod

Check required implementations when an enclosing interface is implemented (#6522)

If an interface contains `require impls`, then implementing the
interface requires each of the `require impls` statements to be true at
the point of the impl definition for the containing interface.
Dana Jansens 3 månader sedan
förälder
incheckning
3a7c44c5c4

+ 2 - 0
toolchain/check/BUILD

@@ -65,6 +65,7 @@ cc_library(
         "pattern.cpp",
         "pattern_match.cpp",
         "pointer_dereference.cpp",
+        "require_impls.cpp",
         "return.cpp",
         "subst.cpp",
         "thunk.cpp",
@@ -128,6 +129,7 @@ cc_library(
         "pending_block.h",
         "pointer_dereference.h",
         "region_stack.h",
+        "require_impls.h",
         "return.h",
         "subst.h",
         "thunk.h",

+ 2 - 1
toolchain/check/custom_witness.cpp

@@ -174,7 +174,8 @@ auto BuildCustomWitness(Context& context, SemIR::LocId loc_id,
         entries.push_back(CheckAssociatedFunctionImplementation(
             context,
             context.types().GetAs<SemIR::FunctionType>(struct_value.type_id),
-            value_id, self_type_id, make_witness(),
+            query_specific_interface.specific_id, value_id, self_type_id,
+            make_witness(),
             /*defer_thunk_definition=*/false));
         break;
       }

+ 4 - 0
toolchain/check/diagnostic_emitter.cpp

@@ -130,6 +130,10 @@ auto DiagnosticEmitter::ConvertArg(llvm::Any arg) const -> llvm::Any {
     sem_ir_->reals().Get(*real_id).Print(out);
     return out.TakeStr();
   }
+  if (auto* specific_interface =
+          llvm::any_cast<SemIR::SpecificInterface>(&arg)) {
+    return StringifySpecificInterface(*sem_ir_, *specific_interface);
+  }
   if (auto* specific_interface_id =
           llvm::any_cast<SemIR::SpecificInterfaceId>(&arg)) {
     auto specific_interface =

+ 1 - 0
toolchain/check/handle_impl.cpp

@@ -348,6 +348,7 @@ auto HandleParseNode(Context& context, Parse::ImplDefinitionStartId node_id)
       context.generics().GetSelfSpecific(impl.generic_id));
   StartGenericDefinition(context, impl.generic_id);
   ImplWitnessStartDefinition(context, impl);
+  CheckRequireDeclsSatisfied(context, impl);
   context.inst_block_stack().Push();
   context.node_stack().Push(node_id, impl_id);
 

+ 63 - 11
toolchain/check/impl.cpp

@@ -12,12 +12,14 @@
 #include "toolchain/check/facet_type.h"
 #include "toolchain/check/function.h"
 #include "toolchain/check/generic.h"
+#include "toolchain/check/impl_lookup.h"
 #include "toolchain/check/import_ref.h"
 #include "toolchain/check/inst.h"
 #include "toolchain/check/interface.h"
 #include "toolchain/check/merge.h"
 #include "toolchain/check/name_lookup.h"
 #include "toolchain/check/name_scope.h"
+#include "toolchain/check/require_impls.h"
 #include "toolchain/check/thunk.h"
 #include "toolchain/check/type.h"
 #include "toolchain/check/type_completion.h"
@@ -43,9 +45,9 @@ static auto NoteAssociatedFunction(Context& context, DiagnosticBuilder& builder,
 
 auto CheckAssociatedFunctionImplementation(
     Context& context, SemIR::FunctionType interface_function_type,
-    SemIR::InstId impl_decl_id, SemIR::TypeId self_type_id,
-    SemIR::InstId witness_inst_id, bool defer_thunk_definition)
-    -> SemIR::InstId {
+    SemIR::SpecificId enclosing_specific_id, SemIR::InstId impl_decl_id,
+    SemIR::TypeId self_type_id, SemIR::InstId witness_inst_id,
+    bool defer_thunk_definition) -> SemIR::InstId {
   auto impl_function_decl =
       context.insts().TryGetAs<SemIR::FunctionDecl>(impl_decl_id);
   if (!impl_function_decl) {
@@ -64,11 +66,6 @@ auto CheckAssociatedFunctionImplementation(
     return SemIR::ErrorInst::InstId;
   }
 
-  auto impl_enclosing_specific_id =
-      context.types()
-          .GetAs<SemIR::FunctionType>(impl_function_decl->type_id)
-          .specific_id;
-
   // Map from the specific for the function type to the specific for the
   // function signature. The function signature may have additional generic
   // parameters.
@@ -79,7 +76,7 @@ auto CheckAssociatedFunctionImplementation(
           context.functions()
               .Get(interface_function_type.function_id)
               .generic_id,
-          impl_enclosing_specific_id, self_type_id, witness_inst_id);
+          enclosing_specific_id, self_type_id, witness_inst_id);
 
   return BuildThunk(context, interface_function_type.function_id,
                     interface_function_specific_id, impl_decl_id,
@@ -632,8 +629,10 @@ auto FinishImplWitness(Context& context, const SemIR::Impl& impl) -> void {
         if (lookup_result.is_found()) {
           used_decl_ids.push_back(lookup_result.target_inst_id());
           witness_value = CheckAssociatedFunctionImplementation(
-              context, *fn_type, lookup_result.target_inst_id(), self_type_id,
-              impl.witness_id, /*defer_thunk_definition=*/true);
+              context, *fn_type,
+              context.generics().GetSelfSpecific(impl.generic_id),
+              lookup_result.target_inst_id(), self_type_id, impl.witness_id,
+              /*defer_thunk_definition=*/true);
         } else {
           CARBON_DIAGNOSTIC(
               ImplMissingFunction, Error,
@@ -664,6 +663,59 @@ auto FinishImplWitness(Context& context, const SemIR::Impl& impl) -> void {
   // TODO: Diagnose if any declarations in the impl are not in used_decl_ids.
 }
 
+auto CheckRequireDeclsSatisfied(Context& context, SemIR::Impl& impl) -> void {
+  if (impl.witness_id == SemIR::ErrorInst::InstId) {
+    return;
+  }
+
+  const auto& interface = context.interfaces().Get(impl.interface.interface_id);
+  auto require_ids =
+      context.require_impls_blocks().Get(interface.require_impls_block_id);
+  for (auto require_id : require_ids) {
+    const auto& require = context.require_impls().Get(require_id);
+
+    auto require_specific =
+        GetRequireImplsSpecificFromEnclosingSpecificWithSelfType(
+            context, require, impl.interface.specific_id, impl.self_id,
+            impl.witness_id);
+    auto self_const_id = GetConstantValueInRequireImplsSpecific(
+        context, require_specific, require.self_id);
+    auto facet_type_const_id = GetConstantValueInRequireImplsSpecific(
+        context, require_specific, require.facet_type_inst_id);
+
+    auto result =
+        LookupImplWitness(context, SemIR::LocId(impl.latest_decl_id()),
+                          self_const_id, facet_type_const_id);
+    // TODO: If the facet type contains 2 interfaces, and one is not `impl`ed,
+    // it would be nice to diagnose which one was not `impl`ed, but that
+    // requires LookupImplWitness to return a partial result, or take a
+    // diagnostic lambda or something.
+    if (!result.has_value()) {
+      auto facet_type_inst_id =
+          context.constant_values().GetInstId(facet_type_const_id);
+
+      if (!result.has_error_value() &&
+          facet_type_inst_id != SemIR::ErrorInst::InstId) {
+        CARBON_DIAGNOSTIC(RequireImplsNotImplemented, Error,
+                          "interface `{0}` being implemented requires that {1} "
+                          "implements {2}",
+                          SemIR::SpecificInterface, SemIR::TypeId,
+                          SemIR::FacetTypeId);
+        context.emitter().Emit(
+            impl.latest_decl_id(), RequireImplsNotImplemented, impl.interface,
+            context.types().GetTypeIdForTypeConstantId(self_const_id),
+            context.insts()
+                .GetAs<SemIR::FacetType>(facet_type_inst_id)
+                .facet_type_id);
+      }
+    }
+    if (!result.has_value() || result.has_error_value()) {
+      FillImplWitnessWithErrors(context, impl);
+      break;
+    }
+  }
+}
+
 auto FillImplWitnessWithErrors(Context& context, SemIR::Impl& impl) -> void {
   if (impl.witness_id == SemIR::ErrorInst::InstId) {
     return;

+ 8 - 3
toolchain/check/impl.h

@@ -61,6 +61,11 @@ auto ImplWitnessStartDefinition(Context& context, SemIR::Impl& impl) -> void;
 // Adds the function members to the witness for `impl`.
 auto FinishImplWitness(Context& context, const SemIR::Impl& impl_id) -> void;
 
+// Checks that any `require` declarations in the interface being implemented by
+// `impl` are satisfied. Otherwise, a diagnostic is issued and the `impl` is
+// made invalid.
+auto CheckRequireDeclsSatisfied(Context& context, SemIR::Impl& impl) -> void;
+
 // Sets all unset members of the witness for `impl` to the error instruction and
 // sets the witness id in the `Impl` to an error.
 auto FillImplWitnessWithErrors(Context& context, SemIR::Impl& impl) -> void;
@@ -75,9 +80,9 @@ auto IsImplEffectivelyFinal(Context& context, const SemIR::Impl& impl) -> bool;
 // `ErrorInst::InstId` if the function is not usable.
 auto CheckAssociatedFunctionImplementation(
     Context& context, SemIR::FunctionType interface_function_type,
-    SemIR::InstId impl_decl_id, SemIR::TypeId self_type_id,
-    SemIR::InstId witness_inst_id, bool defer_thunk_definition)
-    -> SemIR::InstId;
+    SemIR::SpecificId enclosing_specific_id, SemIR::InstId impl_decl_id,
+    SemIR::TypeId self_type_id, SemIR::InstId witness_inst_id,
+    bool defer_thunk_definition) -> SemIR::InstId;
 
 // Checks that the constraint specified for the impl is valid and identified.
 // Returns the interface that the impl implements. On error, issues a diagnostic

+ 11 - 14
toolchain/check/interface.cpp

@@ -81,14 +81,10 @@ static auto GetSelfBinding(Context& context,
   return self_binding_id;
 }
 
-// Given a `Self` type and a witness that it implements an interface, along with
-// that interface's `Self` binding, forms and returns a facet that can be used
-// as the argument for that `Self` binding.
-static auto GetSelfFacet(Context& context,
-                         SemIR::SpecificId interface_specific_id,
-                         SemIR::GenericId generic_id,
-                         SemIR::TypeId self_type_id,
-                         SemIR::InstId self_witness_id) -> SemIR::InstId {
+auto GetSelfFacetValueForInterfaceMemberSpecific(
+    Context& context, SemIR::SpecificId interface_specific_id,
+    SemIR::GenericId generic_id, SemIR::TypeId self_type_id,
+    SemIR::InstId self_witness_id) -> SemIR::InstId {
   auto self_binding_id =
       GetSelfBinding(context, interface_specific_id, generic_id);
   auto self_facet_type_id = SemIR::GetTypeOfInstInSpecific(
@@ -126,8 +122,9 @@ static auto GetGenericArgsWithSelfType(Context& context,
   llvm::append_range(arg_ids, interface_args);
 
   // Add the `Self` argument.
-  arg_ids.push_back(GetSelfFacet(context, interface_specific_id, generic_id,
-                                 self_type_id, witness_inst_id));
+  arg_ids.push_back(GetSelfFacetValueForInterfaceMemberSpecific(
+      context, interface_specific_id, generic_id, self_type_id,
+      witness_inst_id));
 
   return arg_ids;
 }
@@ -212,10 +209,10 @@ auto GetTypeForSpecificAssociatedEntity(Context& context, SemIR::LocId loc_id,
     // type.
     auto interface_fn_type_id = SemIR::GetTypeOfInstInSpecific(
         context.sem_ir(), interface_specific_id, decl_id);
-    auto self_facet_id =
-        GetSelfFacet(context, interface_specific_id,
-                     context.functions().Get(fn->function_id).generic_id,
-                     self_type_id, self_witness_id);
+    auto self_facet_id = GetSelfFacetValueForInterfaceMemberSpecific(
+        context, interface_specific_id,
+        context.functions().Get(fn->function_id).generic_id, self_type_id,
+        self_witness_id);
     return GetFunctionTypeWithSelfType(
         context, context.types().GetInstId(interface_fn_type_id),
         self_facet_id);

+ 17 - 0
toolchain/check/interface.h

@@ -25,6 +25,23 @@ namespace Carbon::Check {
 auto BuildAssociatedEntity(Context& context, SemIR::InterfaceId interface_id,
                            SemIR::InstId decl_id) -> SemIR::InstId;
 
+// Construct a facet value that can be used for the `Self` binding of entities
+// inside an interface.
+//
+// The `interface_specific_id` is the specific of the interface around the
+// `Self`. The `generic_id` is for member of the interface that the `Self` value
+// will be for. The `self_witness_id` is an impl witness for the interface that
+// the `self_type_id` implements that interface. It should come from an impl
+// definition with the given self-type and the interface as its constraint.
+//
+// The returned facet value can be used as the `Self` value in a specific for
+// the generic member of the interface, and can appear in its specific. As such,
+// this is a building block of GetSelfSpecificForInterfaceMemberWithSelfType.
+auto GetSelfFacetValueForInterfaceMemberSpecific(
+    Context& context, SemIR::SpecificId interface_specific_id,
+    SemIR::GenericId generic_id, SemIR::TypeId self_type_id,
+    SemIR::InstId self_witness_id) -> SemIR::InstId;
+
 // Gets the self specific of a generic declaration that is an interface member,
 // given a specific for the interface plus a type to use as `Self`.
 auto GetSelfSpecificForInterfaceMemberWithSelfType(

+ 110 - 0
toolchain/check/require_impls.cpp

@@ -0,0 +1,110 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include "toolchain/check/require_impls.h"
+
+#include "toolchain/check/generic.h"
+#include "toolchain/check/interface.h"
+#include "toolchain/sem_ir/ids.h"
+
+namespace Carbon::Check {
+
+static auto GetEnclosingDeclFromEnclosingSpecificId(
+    Context& context, SemIR::SpecificId enclosing_specific_id) -> SemIR::Inst {
+  return context.insts().Get(
+      context.generics()
+          .Get(context.specifics().Get(enclosing_specific_id).generic_id)
+          .decl_id);
+}
+
+static auto GetSpecificArgsFromEnclosingSpecific(
+    Context& context, SemIR::SpecificId enclosing_specific_id)
+    -> llvm::SmallVector<SemIR::InstId> {
+  auto enclosing_specific_args_id =
+      context.specifics().GetArgsOrEmpty(enclosing_specific_id);
+  auto enclosing_specific_args =
+      context.inst_blocks().Get(enclosing_specific_args_id);
+  llvm::SmallVector<SemIR::InstId> arg_ids;
+  // Reserve space for the `Self` after the enclosing specific's args.
+  arg_ids.reserve(enclosing_specific_args.size() + 1);
+  llvm::append_range(arg_ids, enclosing_specific_args);
+  return arg_ids;
+}
+
+auto GetRequireImplsSpecificFromEnclosingSpecific(
+    Context& context, const SemIR::RequireImpls& require,
+    SemIR::SpecificId enclosing_specific_id) -> RequireImplsSpecific {
+  if (enclosing_specific_id.has_value()) {
+    auto enclosing_generic_decl =
+        GetEnclosingDeclFromEnclosingSpecificId(context, enclosing_specific_id);
+    CARBON_CHECK(enclosing_generic_decl.Is<SemIR::InterfaceDecl>() ||
+                     enclosing_generic_decl.Is<SemIR::NamedConstraintDecl>(),
+                 "Incorrect enclosing specific for RequireImpls. Expected an "
+                 "interface or named constraint. Found {0}.",
+                 enclosing_generic_decl);
+  }
+
+  auto arg_ids =
+      GetSpecificArgsFromEnclosingSpecific(context, enclosing_specific_id);
+
+  // Specifics inside an interface/constraint also include the `Self` of the
+  // enclosing entity. We copy that `Self` from the self-specific of the
+  // RequireImpls generic.
+  const auto& require_generic = context.generics().Get(require.generic_id);
+  const auto& require_self_specific =
+      context.specifics().Get(require_generic.self_specific_id);
+  auto require_self_specific_args =
+      context.inst_blocks().Get(require_self_specific.args_id);
+  // The last argument of a `require` generic is always `Self`, as `require`
+  // can not have any parameters of its own, only enclosing parameters.
+  auto self_inst_id = require_self_specific_args.back();
+  CARBON_CHECK(context.insts().Is<SemIR::SymbolicBinding>(self_inst_id));
+  arg_ids.push_back(self_inst_id);
+
+  auto specific_id = MakeSpecific(context, SemIR::LocId(require.decl_id),
+                                  require.generic_id, arg_ids);
+  // TODO: Cache the specific on Context.
+  return {.specific_id = specific_id};
+}
+
+auto GetRequireImplsSpecificFromEnclosingSpecificWithSelfType(
+    Context& context, const SemIR::RequireImpls& require,
+    SemIR::SpecificId enclosing_specific_id, SemIR::TypeInstId self_id,
+    SemIR::InstId witness_id) -> RequireImplsSpecific {
+  if (enclosing_specific_id.has_value()) {
+    auto enclosing_generic_decl =
+        GetEnclosingDeclFromEnclosingSpecificId(context, enclosing_specific_id);
+    CARBON_CHECK(enclosing_generic_decl.Is<SemIR::InterfaceDecl>(),
+                 "Incorrect enclosing specific for RequireImpls with explicit "
+                 "self type. Expected an interface. Found {0}.",
+                 enclosing_generic_decl);
+  }
+
+  // Construct a facet value around the `self_id` type of the correct facet
+  // type for the `Self` in the require's self-specific.
+  auto self_facet_value = GetSelfFacetValueForInterfaceMemberSpecific(
+      context, enclosing_specific_id, require.generic_id,
+      context.types().GetTypeIdForTypeInstId(self_id), witness_id);
+
+  auto arg_ids =
+      GetSpecificArgsFromEnclosingSpecific(context, enclosing_specific_id);
+  arg_ids.push_back(self_facet_value);
+
+  auto specific_id = MakeSpecific(context, SemIR::LocId(require.decl_id),
+                                  require.generic_id, arg_ids);
+  // TODO: Cache the specific on Context.
+  return {.specific_id = specific_id};
+}
+
+auto GetConstantValueInRequireImplsSpecific(Context& context,
+                                            RequireImplsSpecific specific,
+                                            SemIR::InstId inst_id)
+    -> SemIR::ConstantId {
+  auto const_id = SemIR::GetConstantValueInSpecific(
+      context.sem_ir(), specific.specific_id, inst_id);
+  CARBON_CHECK(const_id.has_value(), "The specific has not been resolved?");
+  return const_id;
+}
+
+}  // namespace Carbon::Check

+ 60 - 0
toolchain/check/require_impls.h

@@ -0,0 +1,60 @@
+// 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
+
+#ifndef CARBON_TOOLCHAIN_CHECK_REQUIRE_IMPLS_H_
+#define CARBON_TOOLCHAIN_CHECK_REQUIRE_IMPLS_H_
+
+#include "toolchain/check/context.h"
+#include "toolchain/sem_ir/ids.h"
+#include "toolchain/sem_ir/require_impls.h"
+
+namespace Carbon::Check {
+
+// A type-safe wrapper around the specific id of a RequireImpls entity.
+// Constructed from a specific for its enclosing interface or constraint entity.
+struct RequireImplsSpecific {
+  SemIR::SpecificId specific_id;
+};
+
+// Get the specific of a RequireImpls from the specific of its enclosing
+// interface or named constraint. Since a `require` declaration can not
+// introduce new generic bindings, the specific for the RequireImpls can be
+// constructed from the enclosing one.
+auto GetRequireImplsSpecificFromEnclosingSpecific(
+    Context& context, const SemIR::RequireImpls& require,
+    SemIR::SpecificId enclosing_specific_id) -> RequireImplsSpecific;
+
+// Like GetRequireImplsSpecificFromEnclosingSpecific but the `Self` value in the
+// specific is replaced by a facet value.
+//
+// The self facet value must have a facet type to match the type of `Self` in
+// specific, which will be a facet type for the enclosing interface. The self
+// type comes from `self_id`, and the `witness_id` must be an impl witness for
+// the enclosing interface.
+//
+// This is only possible for an enclosing interface since we do not ever have an
+// impl witness for a named constraint.
+auto GetRequireImplsSpecificFromEnclosingSpecificWithSelfType(
+    Context& context, const SemIR::RequireImpls& require,
+    SemIR::SpecificId enclosing_specific_id, SemIR::TypeInstId self_id,
+    SemIR::InstId witness_id) -> RequireImplsSpecific;
+
+// Returns the constant value of `inst_id` from inside a RequireImpls
+// declaration, mapped into `enclosing_specific_id`. If an error results, it
+// returns ErrorInst.
+//
+// An error can occur during monomorphization when the self-type was valid as a
+// symbolic but becomes invalid with a more concrete specific.
+//
+// RequireImpls is always generic, so the instructions inside it must have a
+// specific applied. That specific is constructed from a specific for the
+// enclosing generic entity, with GetRequireImplsSpecificFromEnclosingSpecific.
+auto GetConstantValueInRequireImplsSpecific(Context& context,
+                                            RequireImplsSpecific specific,
+                                            SemIR::InstId inst_id)
+    -> SemIR::ConstantId;
+
+}  // namespace Carbon::Check
+
+#endif  // CARBON_TOOLCHAIN_CHECK_REQUIRE_IMPLS_H_

+ 98 - 7
toolchain/check/testdata/facet/require_satisified.carbon

@@ -2,7 +2,7 @@
 // Exceptions. See /LICENSE for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
-// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/none.carbon
+// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/convert.carbon
 //
 // AUTOUPDATE
 // TIP: To test this file alone, run:
@@ -10,7 +10,7 @@
 // TIP: To dump output, run:
 // TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/facet/require_satisified.carbon
 
-// --- todo_fail_missing_require_for_concrete_type.carbon
+// --- fail_missing_require_for_concrete_type.carbon
 library "[[@TEST_NAME]]";
 
 interface Z {}
@@ -22,11 +22,14 @@ interface Y {
 // () does not need to impl Z yet.
 impl () as Y;
 
-// TODO: This should be an error. () needs to impl Z at the start of the
-// definition.
+// () needs to impl Z at the start of the definition.
+// CHECK:STDERR: fail_missing_require_for_concrete_type.carbon:[[@LINE+4]]:1: error: interface `Y` being implemented requires that `()` implements `Z` [RequireImplsNotImplemented]
+// CHECK:STDERR: impl () as Y {}
+// CHECK:STDERR: ^~~~~~~~~~~~~~
+// CHECK:STDERR:
 impl () as Y {}
 
-// --- todo_fail_missing_require_for_symbolic_type.carbon
+// --- fail_missing_require_for_symbolic_type.carbon
 library "[[@TEST_NAME]]";
 
 interface Z {}
@@ -38,10 +41,32 @@ interface Y {
 // T does not need to impl Z yet.
 impl forall [T:! type] T as Y;
 
-// TODO: This should be an error. T needs to impl Z at the start of the
-// definition.
+// T needs to impl Z at the start of the definition.
+// CHECK:STDERR: fail_missing_require_for_symbolic_type.carbon:[[@LINE+4]]:1: error: interface `Y` being implemented requires that `T` implements `Z` [RequireImplsNotImplemented]
+// CHECK:STDERR: impl forall [T:! type] T as Y {}
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR:
 impl forall [T:! type] T as Y {}
 
+// --- fail_missing_require_double.carbon
+library "[[@TEST_NAME]]";
+
+interface Z1(T:! type) {}
+interface Z2(T:! type) {}
+
+class A;
+class B;
+
+interface Y(U:! type) {
+  extend require impls Z1(U) & Z2(B);
+}
+
+// CHECK:STDERR: fail_missing_require_double.carbon:[[@LINE+4]]:1: error: interface `Y(A)` being implemented requires that `()` implements `Z1(A) & Z2(B)` [RequireImplsNotImplemented]
+// CHECK:STDERR: impl () as Y(A) {}
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~
+// CHECK:STDERR:
+impl () as Y(A) {}
+
 // --- require_for_concrete_type.carbon
 library "[[@TEST_NAME]]";
 
@@ -93,3 +118,69 @@ interface Y {
 
 // This only matches T that impl Z so no error here.
 impl forall [T:! Z] T as Y {}
+
+// --- require_for_generic_interfaces.carbon
+library "[[@TEST_NAME]]";
+
+interface Z1(T:! type) {}
+interface Z2(T:! type) {}
+
+class A;
+class B;
+
+interface Y(U:! type) {
+  extend require impls Z1(U) & Z2(B);
+}
+
+// () does not need to impl Z1(A) and Z2(B) yet.
+impl () as Y(A);
+
+// Now we know () impls Z1(A) and Z2(B).
+impl () as Z1(A);
+impl () as Z2(B);
+
+// So no error here.
+impl () as Y(A) {}
+
+impl () as Z1(A) {}
+impl () as Z2(B) {}
+
+// --- fail_require_non_self_missing.carbon
+library "[[@TEST_NAME]]";
+
+interface Z(T:! type) {}
+
+class C;
+
+interface Y(U:! type) {
+  // `Self` must appear somewhere in the require decl, so it's in the interface
+  // specific because we want to test a different self-type.
+  require C impls Z(Self);
+}
+
+// Y requires that C impls Z(Self), but it does not do so.
+// CHECK:STDERR: fail_require_non_self_missing.carbon:[[@LINE+4]]:1: error: interface `Y(())` being implemented requires that `C` implements `Z(())` [RequireImplsNotImplemented]
+// CHECK:STDERR: impl () as Y(()) {}
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~
+// CHECK:STDERR:
+impl () as Y(()) {}
+
+// --- require_non_self.carbon
+library "[[@TEST_NAME]]";
+
+interface Z(T:! type) {}
+
+class C;
+
+interface Y(U:! type) {
+  // `Self` must appear somewhere in the require decl, so it's in the interface
+  // specific because we want to test a different self-type.
+  require C impls Z(Self);
+}
+
+impl C as Z(());
+
+// Y requires that C impls Z(Self), which is done above.
+impl () as Y(Self) {}
+
+impl C as Z(()) {}

+ 57 - 28
toolchain/check/testdata/impl/import_generic.carbon

@@ -25,6 +25,8 @@ impl library "[[@TEST_NAME]]";
 
 class C {}
 
+impl C as I({}) {}
+
 impl C as J({}) {}
 
 // --- basic_import_generic_constraint.carbon
@@ -306,26 +308,30 @@ impl forall [T:! type] D as N(T*) {}
 // CHECK:STDOUT:   %C: type = class_type @C [concrete]
 // CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete]
 // CHECK:STDOUT:   %complete_type.357: <witness> = complete_type_witness %empty_struct_type [concrete]
+// CHECK:STDOUT:   %I.type.609: type = generic_interface_type @I [concrete]
+// CHECK:STDOUT:   %I.generic: %I.type.609 = struct_value () [concrete]
+// CHECK:STDOUT:   %T: type = symbolic_binding T, 0 [symbolic]
+// CHECK:STDOUT:   %I.type.1ab: type = facet_type <@I, @I(%T)> [symbolic]
+// CHECK:STDOUT:   %Self.c1b: %I.type.1ab = symbolic_binding Self, 1 [symbolic]
+// CHECK:STDOUT:   %empty_struct: %empty_struct_type = struct_value () [concrete]
+// CHECK:STDOUT:   %I.type.ab5: type = facet_type <@I, @I(%empty_struct_type)> [concrete]
+// CHECK:STDOUT:   %I.impl_witness: <witness> = impl_witness @C.as.I.impl.%I.impl_witness_table [concrete]
+// CHECK:STDOUT:   %Self.025: %I.type.ab5 = symbolic_binding Self, 1 [symbolic]
 // CHECK:STDOUT:   %J.type.885: type = generic_interface_type @J [concrete]
 // CHECK:STDOUT:   %J.generic: %J.type.885 = struct_value () [concrete]
-// CHECK:STDOUT:   %T: type = symbolic_binding T, 0 [symbolic]
 // CHECK:STDOUT:   %J.type.04e: type = facet_type <@J, @J(%T)> [symbolic]
 // CHECK:STDOUT:   %Self.c25: %J.type.04e = symbolic_binding Self, 1 [symbolic]
-// CHECK:STDOUT:   %I.type.1ab: type = facet_type <@I, @I(%T)> [symbolic]
-// CHECK:STDOUT:   %Self.c1b: %I.type.1ab = symbolic_binding Self, 1 [symbolic]
 // CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 1, %Self.c25 [symbolic]
 // CHECK:STDOUT:   %require_complete: <witness> = require_complete_type %I.type.1ab [symbolic]
-// CHECK:STDOUT:   %empty_struct: %empty_struct_type = struct_value () [concrete]
 // CHECK:STDOUT:   %J.type.d6f: type = facet_type <@J, @J(%empty_struct_type)> [concrete]
 // CHECK:STDOUT:   %J.impl_witness: <witness> = impl_witness @C.as.J.impl.%J.impl_witness_table [concrete]
 // CHECK:STDOUT:   %Self.9e4: %J.type.d6f = symbolic_binding Self, 1 [symbolic]
-// CHECK:STDOUT:   %I.type.ab5: type = facet_type <@I, @I(%empty_struct_type)> [concrete]
-// CHECK:STDOUT:   %Self.025: %I.type.ab5 = symbolic_binding Self, 1 [symbolic]
 // CHECK:STDOUT:   %complete_type.5b1: <witness> = complete_type_witness %I.type.ab5 [concrete]
+// CHECK:STDOUT:   %J.facet: %J.type.d6f = facet_value %C, (%J.impl_witness) [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %Main.I = import_ref Main//basic_import_generic_interface, I, unloaded
+// CHECK:STDOUT:   %Main.I: %I.type.609 = import_ref Main//basic_import_generic_interface, I, loaded [concrete = constants.%I.generic]
 // CHECK:STDOUT:   %Main.J: %J.type.885 = import_ref Main//basic_import_generic_interface, J, loaded [concrete = constants.%J.generic]
 // CHECK:STDOUT:   %Main.import_ref.3fa = import_ref Main//basic_import_generic_interface, loc3_23, unloaded
 // CHECK:STDOUT:   %Main.import_ref.b3bc94.1: type = import_ref Main//basic_import_generic_interface, loc3_13, loaded [symbolic = @I.%T (constants.%T)]
@@ -346,49 +352,56 @@ impl forall [T:! type] D as N(T*) {}
 // CHECK:STDOUT:   %default.import.loc1_46.1 = import <none>
 // CHECK:STDOUT:   %default.import.loc1_46.2 = import <none>
 // CHECK:STDOUT:   %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
-// CHECK:STDOUT:   impl_decl @C.as.J.impl [concrete] {} {
+// CHECK:STDOUT:   impl_decl @C.as.I.impl [concrete] {} {
 // CHECK:STDOUT:     %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C]
-// CHECK:STDOUT:     %J.ref: %J.type.885 = name_ref J, imports.%Main.J [concrete = constants.%J.generic]
+// CHECK:STDOUT:     %I.ref: %I.type.609 = name_ref I, imports.%Main.I [concrete = constants.%I.generic]
 // CHECK:STDOUT:     %.loc5_14: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct]
 // CHECK:STDOUT:     %.loc5_15: type = converted %.loc5_14, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
+// CHECK:STDOUT:     %I.type: type = facet_type <@I, @I(constants.%empty_struct_type)> [concrete = constants.%I.type.ab5]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   impl_decl @C.as.J.impl [concrete] {} {
+// CHECK:STDOUT:     %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C]
+// CHECK:STDOUT:     %J.ref: %J.type.885 = name_ref J, imports.%Main.J [concrete = constants.%J.generic]
+// CHECK:STDOUT:     %.loc7_14: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct]
+// CHECK:STDOUT:     %.loc7_15: type = converted %.loc7_14, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
 // CHECK:STDOUT:     %J.type: type = facet_type <@J, @J(constants.%empty_struct_type)> [concrete = constants.%J.type.d6f]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: generic interface @J(imports.%Main.import_ref.b3bc94.3: type) [from "basic_import_generic_interface.carbon"] {
+// CHECK:STDOUT: generic interface @I(imports.%Main.import_ref.b3bc94.1: type) [from "basic_import_generic_interface.carbon"] {
 // CHECK:STDOUT:   %T: type = symbolic_binding T, 0 [symbolic = %T (constants.%T)]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !definition:
-// CHECK:STDOUT:   %J.type: type = facet_type <@J, @J(%T)> [symbolic = %J.type (constants.%J.type.04e)]
-// CHECK:STDOUT:   %Self: @J.%J.type (%J.type.04e) = symbolic_binding Self, 1 [symbolic = %Self (constants.%Self.c25)]
 // CHECK:STDOUT:   %I.type: type = facet_type <@I, @I(%T)> [symbolic = %I.type (constants.%I.type.1ab)]
-// CHECK:STDOUT:   %require_complete: <witness> = require_complete_type %I.type [symbolic = %require_complete (constants.%require_complete)]
+// CHECK:STDOUT:   %Self: @I.%I.type (%I.type.1ab) = symbolic_binding Self, 1 [symbolic = %Self (constants.%Self.c1b)]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   interface {
 // CHECK:STDOUT:   !members:
-// CHECK:STDOUT:     .Self = imports.%Main.import_ref.e9b
+// CHECK:STDOUT:     .Self = imports.%Main.import_ref.3fa
 // CHECK:STDOUT:     witness = ()
 // CHECK:STDOUT:
 // CHECK:STDOUT:   !requires:
-// CHECK:STDOUT:     @J.require50000000 {
-// CHECK:STDOUT:       require imports.%Main.import_ref.2ff impls imports.%Main.import_ref.358
-// CHECK:STDOUT:     }
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: generic interface @I(imports.%Main.import_ref.b3bc94.1: type) [from "basic_import_generic_interface.carbon"] {
+// CHECK:STDOUT: generic interface @J(imports.%Main.import_ref.b3bc94.3: type) [from "basic_import_generic_interface.carbon"] {
 // CHECK:STDOUT:   %T: type = symbolic_binding T, 0 [symbolic = %T (constants.%T)]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %J.type: type = facet_type <@J, @J(%T)> [symbolic = %J.type (constants.%J.type.04e)]
+// CHECK:STDOUT:   %Self: @J.%J.type (%J.type.04e) = symbolic_binding Self, 1 [symbolic = %Self (constants.%Self.c25)]
 // CHECK:STDOUT:   %I.type: type = facet_type <@I, @I(%T)> [symbolic = %I.type (constants.%I.type.1ab)]
-// CHECK:STDOUT:   %Self: @I.%I.type (%I.type.1ab) = symbolic_binding Self, 1 [symbolic = %Self (constants.%Self.c1b)]
+// CHECK:STDOUT:   %require_complete: <witness> = require_complete_type %I.type [symbolic = %require_complete (constants.%require_complete)]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   interface {
 // CHECK:STDOUT:   !members:
-// CHECK:STDOUT:     .Self = imports.%Main.import_ref.3fa
+// CHECK:STDOUT:     .Self = imports.%Main.import_ref.e9b
 // CHECK:STDOUT:     witness = ()
 // CHECK:STDOUT:
 // CHECK:STDOUT:   !requires:
+// CHECK:STDOUT:     @J.require50000000 {
+// CHECK:STDOUT:       require imports.%Main.import_ref.2ff impls imports.%Main.import_ref.358
+// CHECK:STDOUT:     }
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -400,6 +413,14 @@ impl forall [T:! type] D as N(T*) {}
 // CHECK:STDOUT:   %I.type: type = facet_type <@I, @I(%T)> [symbolic = %I.type (constants.%I.type.1ab)]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: impl @C.as.I.impl: %C.ref as %I.type {
+// CHECK:STDOUT:   %I.impl_witness_table = impl_witness_table (), @C.as.I.impl [concrete]
+// CHECK:STDOUT:   %I.impl_witness: <witness> = impl_witness %I.impl_witness_table [concrete = constants.%I.impl_witness]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   witness = %I.impl_witness
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: impl @C.as.J.impl: %C.ref as %J.type {
 // CHECK:STDOUT:   %J.impl_witness_table = impl_witness_table (), @C.as.J.impl [concrete]
 // CHECK:STDOUT:   %J.impl_witness: <witness> = impl_witness %J.impl_witness_table [concrete = constants.%J.impl_witness]
@@ -416,10 +437,6 @@ impl forall [T:! type] D as N(T*) {}
 // CHECK:STDOUT:   .Self = constants.%C
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: specific @J(constants.%T) {
-// CHECK:STDOUT:   %T => constants.%T
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
 // CHECK:STDOUT: specific @I(constants.%T) {
 // CHECK:STDOUT:   %T => constants.%T
 // CHECK:STDOUT:
@@ -428,6 +445,18 @@ impl forall [T:! type] D as N(T*) {}
 // CHECK:STDOUT:   %Self => constants.%Self.c1b
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: specific @I(constants.%empty_struct_type) {
+// CHECK:STDOUT:   %T => constants.%empty_struct_type
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %I.type => constants.%I.type.ab5
+// CHECK:STDOUT:   %Self => constants.%Self.025
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @J(constants.%T) {
+// CHECK:STDOUT:   %T => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: specific @J.require50000000(constants.%T, constants.%Self.c25) {
 // CHECK:STDOUT:   %T => constants.%T
 // CHECK:STDOUT:   %J.type => constants.%J.type.04e
@@ -446,12 +475,12 @@ impl forall [T:! type] D as N(T*) {}
 // CHECK:STDOUT:   %require_complete => constants.%complete_type.5b1
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: specific @I(constants.%empty_struct_type) {
+// CHECK:STDOUT: specific @J.require50000000(constants.%empty_struct_type, constants.%J.facet) {
 // CHECK:STDOUT:   %T => constants.%empty_struct_type
-// CHECK:STDOUT:
-// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %J.type => constants.%J.type.d6f
+// CHECK:STDOUT:   %Self => constants.%J.facet
+// CHECK:STDOUT:   %Self.binding.as_type => constants.%C
 // CHECK:STDOUT:   %I.type => constants.%I.type.ab5
-// CHECK:STDOUT:   %Self => constants.%Self.025
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- basic_import_generic_constraint.carbon

+ 62 - 22
toolchain/check/testdata/impl/incomplete.carbon

@@ -185,12 +185,14 @@ constraint Y {
   require impls Z;
 }
 interface X {
+  let X1:! type;
+
   // Not extend, so only required to be identified.
   require impls Y;
 }
 
-class C {}
-impl C as X {}
+// Requires `X` to be complete, doesn't require Z to be complete.
+fn F(T:! X where .X1 = {}) {}
 
 // --- fail_incomplete_constraint.carbon
 library "[[@TEST_NAME]]";
@@ -736,11 +738,22 @@ interface B {
 // CHECK:STDOUT:   %Self.binding.as_type.5cb: type = symbolic_binding_type Self, 0, %Self.550 [symbolic]
 // CHECK:STDOUT:   %X.type: type = facet_type <@X> [concrete]
 // CHECK:STDOUT:   %Self.e52: %X.type = symbolic_binding Self, 0 [symbolic]
+// CHECK:STDOUT:   %X.assoc_type: type = assoc_entity_type @X [concrete]
+// CHECK:STDOUT:   %assoc0: %X.assoc_type = assoc_entity element0, @X.%X1 [concrete]
 // CHECK:STDOUT:   %Self.binding.as_type.806: type = symbolic_binding_type Self, 0, %Self.e52 [symbolic]
-// CHECK:STDOUT:   %C: type = class_type @C [concrete]
+// CHECK:STDOUT:   %type: type = facet_type <type> [concrete]
+// CHECK:STDOUT:   %.Self.c39: %type = symbolic_binding .Self [symbolic_self]
+// CHECK:STDOUT:   %.Self.637: %X.type = symbolic_binding .Self [symbolic_self]
+// CHECK:STDOUT:   %.Self.binding.as_type: type = symbolic_binding_type .Self, %.Self.637 [symbolic_self]
+// CHECK:STDOUT:   %X.lookup_impl_witness: <witness> = lookup_impl_witness %.Self.637, @X [symbolic_self]
+// CHECK:STDOUT:   %impl.elem0: type = impl_witness_access %X.lookup_impl_witness, element0 [symbolic_self]
 // CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete]
-// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete]
-// CHECK:STDOUT:   %X.impl_witness: <witness> = impl_witness @C.as.X.impl.%X.impl_witness_table [concrete]
+// CHECK:STDOUT:   %empty_struct: %empty_struct_type = struct_value () [concrete]
+// CHECK:STDOUT:   %X_where.type: type = facet_type <@X where %impl.elem0 = %empty_struct_type> [concrete]
+// CHECK:STDOUT:   %T: %X_where.type = symbolic_binding T, 0 [symbolic]
+// CHECK:STDOUT:   %pattern_type: type = pattern_type %X_where.type [concrete]
+// CHECK:STDOUT:   %F.type: type = fn_type @F [concrete]
+// CHECK:STDOUT:   %F: %F.type = struct_value () [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -748,15 +761,31 @@ interface B {
 // CHECK:STDOUT:     .Z = %Z.decl
 // CHECK:STDOUT:     .Y = %Y.decl
 // CHECK:STDOUT:     .X = %X.decl
-// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .F = %F.decl
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Z.decl: type = interface_decl @Z [concrete = constants.%Z.type] {} {}
 // CHECK:STDOUT:   %Y.decl: type = constraint_decl @Y [concrete = constants.%Y.type] {} {}
 // CHECK:STDOUT:   %X.decl: type = interface_decl @X [concrete = constants.%X.type] {} {}
-// CHECK:STDOUT:   %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
-// CHECK:STDOUT:   impl_decl @C.as.X.impl [concrete] {} {
-// CHECK:STDOUT:     %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C]
-// CHECK:STDOUT:     %X.ref: type = name_ref X, file.%X.decl [concrete = constants.%X.type]
+// CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {
+// CHECK:STDOUT:     %T.patt: %pattern_type = symbolic_binding_pattern T, 0 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %.loc16_12.1: type = splice_block %.loc16_12.2 [concrete = constants.%X_where.type] {
+// CHECK:STDOUT:       %.Self.1: %type = symbolic_binding .Self [symbolic_self = constants.%.Self.c39]
+// CHECK:STDOUT:       %X.ref: type = name_ref X, file.%X.decl [concrete = constants.%X.type]
+// CHECK:STDOUT:       %.Self.2: %X.type = symbolic_binding .Self [symbolic_self = constants.%.Self.637]
+// CHECK:STDOUT:       %.Self.ref: %X.type = name_ref .Self, %.Self.2 [symbolic_self = constants.%.Self.637]
+// CHECK:STDOUT:       %X1.ref: %X.assoc_type = name_ref X1, @X1.%assoc0 [concrete = constants.%assoc0]
+// CHECK:STDOUT:       %.Self.as_type: type = facet_access_type %.Self.ref [symbolic_self = constants.%.Self.binding.as_type]
+// CHECK:STDOUT:       %.loc16_18: type = converted %.Self.ref, %.Self.as_type [symbolic_self = constants.%.Self.binding.as_type]
+// CHECK:STDOUT:       %impl.elem0: type = impl_witness_access constants.%X.lookup_impl_witness, element0 [symbolic_self = constants.%impl.elem0]
+// CHECK:STDOUT:       %.loc16_25.1: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct]
+// CHECK:STDOUT:       %.loc16_25.2: type = converted %.loc16_25.1, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
+// CHECK:STDOUT:       %.loc16_12.2: type = where_expr %.Self.2 [concrete = constants.%X_where.type] {
+// CHECK:STDOUT:         requirement_base_facet_type constants.%X.type
+// CHECK:STDOUT:         requirement_rewrite %impl.elem0, %.loc16_25.2
+// CHECK:STDOUT:       }
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:     %T.loc16_6.2: %X_where.type = symbolic_binding T, 0 [symbolic = %T.loc16_6.1 (constants.%T)]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -764,6 +793,9 @@ interface B {
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @X {
 // CHECK:STDOUT:   %Self: %X.type = symbolic_binding Self, 0 [symbolic = constants.%Self.e52]
+// CHECK:STDOUT:   %X1: type = assoc_const_decl @X1 [concrete] {
+// CHECK:STDOUT:     %assoc0: %X.assoc_type = assoc_entity element0, @X.%X1 [concrete = constants.%assoc0]
+// CHECK:STDOUT:   }
 // CHECK:STDOUT:   %X.require54000001.decl = require_decl @X.require54000001 [concrete] {
 // CHECK:STDOUT:     require %Self.as_type impls %Y.ref
 // CHECK:STDOUT:   } {
@@ -773,8 +805,9 @@ interface B {
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   .X1 = @X1.%assoc0
 // CHECK:STDOUT:   .Y = <poisoned>
-// CHECK:STDOUT:   witness = ()
+// CHECK:STDOUT:   witness = (%X1)
 // CHECK:STDOUT:
 // CHECK:STDOUT: !requires:
 // CHECK:STDOUT:   @X.require54000001 {
@@ -811,20 +844,19 @@ interface B {
 // CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type.806)]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @C.as.X.impl: %C.ref as %X.ref {
-// CHECK:STDOUT:   %X.impl_witness_table = impl_witness_table (), @C.as.X.impl [concrete]
-// CHECK:STDOUT:   %X.impl_witness: <witness> = impl_witness %X.impl_witness_table [concrete = constants.%X.impl_witness]
-// CHECK:STDOUT:
-// CHECK:STDOUT: !members:
-// CHECK:STDOUT:   witness = %X.impl_witness
+// CHECK:STDOUT: generic assoc_const @X1(@X.%Self: %X.type) {
+// CHECK:STDOUT:   assoc_const X1:! type;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: class @C {
-// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness constants.%empty_struct_type [concrete = constants.%complete_type]
-// CHECK:STDOUT:   complete_type_witness = %complete_type
+// CHECK:STDOUT: generic fn @F(%T.loc16_6.2: %X_where.type) {
+// CHECK:STDOUT:   %T.loc16_6.1: %X_where.type = symbolic_binding T, 0 [symbolic = %T.loc16_6.1 (constants.%T)]
 // CHECK:STDOUT:
-// CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn() {
+// CHECK:STDOUT:   !entry:
+// CHECK:STDOUT:     return
+// CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @Y.require54000000(constants.%Self.550) {
@@ -832,11 +864,19 @@ interface B {
 // CHECK:STDOUT:   %Self.binding.as_type => constants.%Self.binding.as_type.5cb
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: specific @X1(constants.%Self.e52) {}
+// CHECK:STDOUT:
 // CHECK:STDOUT: specific @X.require54000001(constants.%Self.e52) {
 // CHECK:STDOUT:   %Self => constants.%Self.e52
 // CHECK:STDOUT:   %Self.binding.as_type => constants.%Self.binding.as_type.806
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: specific @X1(constants.%.Self.637) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F(constants.%T) {
+// CHECK:STDOUT:   %T.loc16_6.1 => constants.%T
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_incomplete_constraint.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {

+ 15 - 51
toolchain/check/type_completion.cpp

@@ -11,6 +11,7 @@
 #include "toolchain/check/generic.h"
 #include "toolchain/check/inst.h"
 #include "toolchain/check/literal.h"
+#include "toolchain/check/require_impls.h"
 #include "toolchain/check/type.h"
 #include "toolchain/diagnostics/format_providers.h"
 #include "toolchain/sem_ir/constant.h"
@@ -804,56 +805,23 @@ static auto RequireIdentifiedNamedConstraints(
   return true;
 }
 
-// Get the specific of a RequireImpls from the specific of its enclosing
-// interface or named constraint. Since a `require` declaration can not
-// introduce new generic bindings, the specific for the RequireImpls can be
-// constructed from the enclosing one.
-static auto GetRequireImplsSpecificFromEnclosingSpecific(
-    Context& context, const SemIR::RequireImpls& require,
-    SemIR::SpecificId enclosing_specific_id) -> SemIR::SpecificId {
-  auto enclosing_specific_args_id =
-      context.specifics().GetArgsOrEmpty(enclosing_specific_id);
-  auto enclosing_specific_args =
-      context.inst_blocks().Get(enclosing_specific_args_id);
-  llvm::SmallVector<SemIR::InstId> arg_ids;
-  arg_ids.reserve(enclosing_specific_args.size() + 1);
-  // Start with the args from the enclosing specific.
-  llvm::append_range(arg_ids, enclosing_specific_args);
-
-  // Specifics inside an interface/constraint also include the `Self` of the
-  // enclosing entity. We copy that `Self` from the self-specific of the
-  // RequireImpls generic.
-  const auto& require_generic = context.generics().Get(require.generic_id);
-  const auto& require_self_specific =
-      context.specifics().Get(require_generic.self_specific_id);
-  auto require_self_specific_args =
-      context.inst_blocks().Get(require_self_specific.args_id);
-  // The last argument of a `require` generic is always `Self`, as `require` can
-  // not have any parameters of its own, only enclosing parameters.
-  auto self_inst_id = require_self_specific_args.back();
-  CARBON_CHECK(context.insts().Is<SemIR::SymbolicBinding>(self_inst_id));
-  arg_ids.push_back(self_inst_id);
-
-  return MakeSpecific(context, SemIR::LocId(require.decl_id),
-                      require.generic_id, arg_ids);
-}
-
 // Returns the `facet_type` mapped into `specific_id`. If an error results, it
 // returns None. In particular, this can surface as a monomorphization error
 // where the facet type was valid as a symbolic but becomes invalid with some
 // concrete specific.
-static auto TryGetFacetTypeInSpecific(Context& context,
-                                      SemIR::InstId facet_type,
-                                      SemIR::SpecificId specific_id)
-    -> SemIR::FacetTypeId {
-  auto const_facet_type = SemIR::GetConstantValueInSpecific(
-      context.sem_ir(), specific_id, facet_type);
-  auto facet_type_in_specific = context.insts().TryGetAs<SemIR::FacetType>(
-      context.constant_values().GetInstId(const_facet_type));
-  if (!facet_type_in_specific.has_value()) {
-    return SemIR::FacetTypeId::None;
+static auto TryGetRequireImplsFacetTypeInEnclosingSpecific(
+    Context& context, const SemIR::RequireImpls& require,
+    SemIR::SpecificId enclosing_specific_id) -> SemIR::FacetTypeId {
+  auto require_specific = GetRequireImplsSpecificFromEnclosingSpecific(
+      context, require, enclosing_specific_id);
+  auto const_id = GetConstantValueInRequireImplsSpecific(
+      context, require_specific, require.facet_type_inst_id);
+  if (auto facet_type_in_specific = context.insts().TryGetAs<SemIR::FacetType>(
+          context.constant_values().GetInstId(const_id))) {
+    return facet_type_in_specific->facet_type_id;
   }
-  return facet_type_in_specific->facet_type_id;
+  // An ErrorInst was encountered.
+  return SemIR::FacetTypeId::None;
 }
 
 auto RequireIdentifiedFacetType(Context& context, SemIR::LocId loc_id,
@@ -917,10 +885,8 @@ auto RequireIdentifiedFacetType(Context& context, SemIR::LocId loc_id,
       for (auto require_impls_id : context.require_impls_blocks().Get(
                constraint.require_impls_block_id)) {
         const auto& require = context.require_impls().Get(require_impls_id);
-        auto require_specific_id = GetRequireImplsSpecificFromEnclosingSpecific(
+        auto facet_type_id = TryGetRequireImplsFacetTypeInEnclosingSpecific(
             context, require, extends.specific_id);
-        auto facet_type_id = TryGetFacetTypeInSpecific(
-            context, require.facet_type_inst_id, require_specific_id);
         if (facet_type_id.has_value()) {
           if (facet_type_extends && require.extend_self) {
             extend_facet_types.push_back(facet_type_id);
@@ -937,10 +903,8 @@ auto RequireIdentifiedFacetType(Context& context, SemIR::LocId loc_id,
       for (auto require_impls_id : context.require_impls_blocks().Get(
                constraint.require_impls_block_id)) {
         const auto& require = context.require_impls().Get(require_impls_id);
-        auto require_specific_id = GetRequireImplsSpecificFromEnclosingSpecific(
+        auto facet_type_id = TryGetRequireImplsFacetTypeInEnclosingSpecific(
             context, require, impls.specific_id);
-        auto facet_type_id = TryGetFacetTypeInSpecific(
-            context, require.facet_type_inst_id, require_specific_id);
         if (facet_type_id.has_value()) {
           impls_facet_types.push_back(facet_type_id);
         }

+ 1 - 0
toolchain/diagnostics/diagnostic_kind.def

@@ -366,6 +366,7 @@ CARBON_DIAGNOSTIC_KIND(RequireImplsMissingFacetType)
 CARBON_DIAGNOSTIC_KIND(RequireImplsMissingSelf)
 CARBON_DIAGNOSTIC_KIND(RequireImplsIncompleteFacetType)
 CARBON_DIAGNOSTIC_KIND(RequireImplsUnidentifiedFacetType)
+CARBON_DIAGNOSTIC_KIND(RequireImplsNotImplemented)
 CARBON_DIAGNOSTIC_KIND(RequireInWrongScope)
 
 // Let declaration checking.