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

Generate a RequireDecl instruction for require declarations (#6318)

The `RequireDecl` instruction points, via a `RequireImplsId` to a
`RequireImpls` structure in a `ValueStore`. That structure holds the
self-type and facet type, as well as the generic id and parent scope.
`RequireImpls` is always a generic since it only appears in an
`interface` or `constraint`, which both have a generic parameter `Self`
applied to all their members.

The `RequireDecl` instruction evaluates to itself, but drops the
decl_block_id since the instructions within the `require` declaration
are not required in the canonical value which is only used for import.
And import will want to import the `RequireImpls` structure along with
the `Interface` or `NamedConstraint` structure it is in, rather than
recreate it from the decl's instructions. This also avoids repeating all
the instructions within the `require` decl in the textual semir's
constants block.

Adding the `RequireImpls` to the `Interface` or `NamedConstraint`
structure is not yet done, so they are not available for impl lookup or
import yet.
Dana Jansens 5 месяцев назад
Родитель
Сommit
81e55bed8a

+ 3 - 0
toolchain/check/context.h

@@ -268,6 +268,9 @@ class Context {
   auto named_constraints() -> SemIR::NamedConstraintStore& {
     return sem_ir().named_constraints();
   }
+  auto require_impls() -> SemIR::RequireImplsStore& {
+    return sem_ir().require_impls();
+  }
   auto associated_constants() -> SemIR::AssociatedConstantStore& {
     return sem_ir().associated_constants();
   }

+ 2 - 0
toolchain/check/handle_impl.cpp

@@ -190,6 +190,7 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId node_id,
                                /*is_extern=*/false, SemIR::LibraryNameId::None),
                            {.self_id = self_type_inst_id,
                             .constraint_id = constraint_type_inst_id,
+                            // This requires that the facet type is identified.
                             .interface = CheckConstraintIsInterface(
                                 context, impl_decl_id, constraint_type_inst_id),
                             .is_final = is_final}};
@@ -230,6 +231,7 @@ auto HandleParseNode(Context& context, Parse::ImplDefinitionStartId node_id)
       impl_decl_id, impl_info.scope_id,
       context.generics().GetSelfSpecific(impl_info.generic_id));
   StartGenericDefinition(context, impl_info.generic_id);
+  // This requires that the facet type is complete.
   ImplWitnessStartDefinition(context, impl_info);
   context.inst_block_stack().Push();
   context.node_stack().Push(node_id, impl_id);

+ 2 - 2
toolchain/check/handle_named_constraint.cpp

@@ -159,11 +159,11 @@ auto HandleParseNode(Context& context,
   auto& constraint_info = context.named_constraints().Get(named_constraint_id);
   constraint_info.complete = true;
 
+  FinishGenericDefinition(context, constraint_info.generic_id);
+
   // TODO: Do something with `require` and `alias` statements in the body of the
   // constraint.
 
-  FinishGenericDefinition(context, constraint_info.generic_id);
-
   // The decl_name_stack and scopes are popped by `ProcessNodeIds`.
   return true;
 }

+ 80 - 26
toolchain/check/handle_require.cpp

@@ -5,12 +5,16 @@
 #include "toolchain/base/kind_switch.h"
 #include "toolchain/check/context.h"
 #include "toolchain/check/convert.h"
+#include "toolchain/check/generic.h"
 #include "toolchain/check/handle.h"
+#include "toolchain/check/inst.h"
 #include "toolchain/check/modifiers.h"
 #include "toolchain/check/name_lookup.h"
 #include "toolchain/check/subst.h"
+#include "toolchain/check/type.h"
 #include "toolchain/check/type_completion.h"
 #include "toolchain/parse/node_ids.h"
+#include "toolchain/sem_ir/ids.h"
 #include "toolchain/sem_ir/named_constraint.h"
 #include "toolchain/sem_ir/type_iterator.h"
 #include "toolchain/sem_ir/typed_insts.h"
@@ -19,6 +23,10 @@ namespace Carbon::Check {
 
 auto HandleParseNode(Context& context, Parse::RequireIntroducerId node_id)
     -> bool {
+  // Require decls are always generic, since everything in an `interface` or
+  // `constraint` is generic over `Self`.
+  StartGenericDecl(context);
+
   // Create an instruction block to hold the instructions created for the type
   // and constraint.
   context.inst_block_stack().Push();
@@ -134,22 +142,18 @@ static auto TypeStructureReferencesSelf(
   return true;
 }
 
-auto HandleParseNode(Context& context, Parse::RequireDeclId node_id) -> bool {
-  auto [constraint_node_id, constraint_inst_id] =
-      context.node_stack().PopExprWithNodeId();
-  auto [self_node_id, self_inst_id] =
-      context.node_stack().PopWithNodeId<Parse::NodeCategory::RequireImpls>();
-
-  [[maybe_unused]] auto decl_block_id = context.inst_block_stack().Pop();
-
-  // Process modifiers.
-  auto introducer =
-      context.decl_introducer_state_stack().Pop<Lex::TokenKind::Require>();
-  LimitModifiersOnDecl(context, introducer, KeywordModifierSet::Extend);
-
-  auto scope_inst_id =
-      context.node_stack().Pop<Parse::NodeKind::RequireIntroducer>();
+struct ValidateRequireResult {
+  SemIR::FacetType facet_type;
+  const SemIR::IdentifiedFacetType* identified;
+};
 
+// Returns nullopt if a diagnostic has been emitted and the `require` decl is
+// not valid.
+static auto ValidateRequire(Context& context, SemIR::LocId loc_id,
+                            SemIR::TypeInstId self_inst_id,
+                            SemIR::InstId constraint_inst_id,
+                            SemIR::InstId scope_inst_id)
+    -> std::optional<ValidateRequireResult> {
   auto constraint_constant_value_inst_id =
       context.constant_values().GetConstantInstId(constraint_inst_id);
   auto constraint_facet_type = context.insts().TryGetAs<SemIR::FacetType>(
@@ -160,10 +164,10 @@ auto HandleParseNode(Context& context, Parse::RequireDeclId node_id) -> bool {
           RequireImplsMissingFacetType, Error,
           "`require` declaration constrained by a non-facet type; "
           "expected an `interface` or `constraint` name after `impls`");
-      context.emitter().Emit(constraint_node_id, RequireImplsMissingFacetType);
+      context.emitter().Emit(constraint_inst_id, RequireImplsMissingFacetType);
     }
     // Can't continue without a constraint to use.
-    return true;
+    return std::nullopt;
   }
 
   auto identified_facet_type_id =
@@ -172,13 +176,14 @@ auto HandleParseNode(Context& context, Parse::RequireDeclId node_id) -> bool {
             RequireImplsUnidentifiedFacetType, Error,
             "facet type {0} cannot be identified in `require` declaration",
             InstIdAsType);
-        return context.emitter().Build(constraint_node_id,
+        return context.emitter().Build(constraint_inst_id,
                                        RequireImplsUnidentifiedFacetType,
                                        constraint_inst_id);
       });
   if (!identified_facet_type_id.has_value()) {
-    // The constraint can't be used.
-    return true;
+    // The constraint can't be used. A diagnostic was emitted by
+    // RequireIdentifiedFacetType().
+    return std::nullopt;
   }
   const auto& identified =
       context.identified_facet_types().Get(identified_facet_type_id);
@@ -188,22 +193,71 @@ auto HandleParseNode(Context& context, Parse::RequireDeclId node_id) -> bool {
                       "no `Self` reference found in `require` declaration; "
                       "`Self` must appear in the self-type or as a generic "
                       "parameter for each `interface` or `constraint`");
-    context.emitter().Emit(node_id, RequireImplsMissingSelf);
-    return true;
+    context.emitter().Emit(loc_id, RequireImplsMissingSelf);
+    return std::nullopt;
   }
 
   if (scope_inst_id == SemIR::ErrorInst::InstId) {
     // `require` is in the wrong scope.
+    return std::nullopt;
+  }
+  if (self_inst_id == SemIR::ErrorInst::InstId ||
+      constraint_inst_id == SemIR::ErrorInst::InstId) {
+    // Can't build a useful `require` with an error, it couldn't do anything.
+    return std::nullopt;
+  }
+
+  return ValidateRequireResult{.facet_type = *constraint_facet_type,
+                               .identified = &identified};
+}
+
+auto HandleParseNode(Context& context, Parse::RequireDeclId node_id) -> bool {
+  auto [constraint_node_id, constraint_inst_id] =
+      context.node_stack().PopExprWithNodeId();
+  auto [self_node_id, self_inst_id] =
+      context.node_stack().PopWithNodeId<Parse::NodeCategory::RequireImpls>();
+
+  auto decl_block_id = context.inst_block_stack().Pop();
+
+  // Process modifiers.
+  auto introducer =
+      context.decl_introducer_state_stack().Pop<Lex::TokenKind::Require>();
+  LimitModifiersOnDecl(context, introducer, KeywordModifierSet::Extend);
+
+  auto scope_inst_id =
+      context.node_stack().Pop<Parse::NodeKind::RequireIntroducer>();
+
+  auto validated = ValidateRequire(context, node_id, self_inst_id,
+                                   constraint_inst_id, scope_inst_id);
+  if (!validated) {
+    DiscardGenericDecl(context);
     return true;
   }
 
-  if (identified.required_interfaces().empty()) {
-    // A `require T impls type` adds no actual constraints.
+  auto [constraint_facet_type, identified] = *validated;
+  if (identified->required_interfaces().empty()) {
+    // A `require T impls type` adds no actual constraints, so nothing to do.
+    DiscardGenericDecl(context);
     return true;
   }
 
-  // TODO: Add the `require` constraint to the InterfaceDecl or ConstraintDecl
-  // from `scope_inst_id`.
+  auto require_impls_decl =
+      SemIR::RequireImplsDecl{// To be filled in after.
+                              .require_impls_id = SemIR::RequireImplsId::None,
+                              .decl_block_id = decl_block_id};
+  auto decl_id = AddPlaceholderInst(context, node_id, require_impls_decl);
+  auto require_impls_id = context.require_impls().Add(
+      {.self_id = self_inst_id,
+       .facet_type_inst_id =
+           context.types().GetAsTypeInstId(constraint_inst_id),
+       .facet_type_id = constraint_facet_type.facet_type_id,
+       .decl_id = decl_id,
+       .parent_scope_id = context.scope_stack().PeekNameScopeId(),
+       .body_block_id = decl_block_id,
+       .generic_id = BuildGenericDecl(context, decl_id)});
+
+  require_impls_decl.require_impls_id = require_impls_id;
+  ReplaceInstBeforeConstantUse(context, decl_id, require_impls_decl);
 
   return true;
 }

+ 108 - 0
toolchain/check/testdata/facet/require_import.carbon

@@ -0,0 +1,108 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/none.carbon
+//
+// AUTOUPDATE
+// TIP: To test this file alone, run:
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/facet/require_import.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/facet/require_import.carbon
+
+// --- a.carbon
+library "[[@TEST_NAME]]";
+
+interface Z {}
+
+interface Y {
+  require impls Z;
+}
+
+constraint X {
+  extend require impls Z;
+}
+
+// --- a.impl.carbon
+//@include-in-dumps
+impl library "[[@TEST_NAME]]";
+
+fn F(A:! X, B:! Y) {}
+
+// CHECK:STDOUT: --- a.impl.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %type: type = facet_type <type> [concrete]
+// CHECK:STDOUT:   %.Self: %type = symbolic_binding .Self [symbolic_self]
+// CHECK:STDOUT:   %X.type: type = facet_type <@X> [concrete]
+// CHECK:STDOUT:   %A: %X.type = symbolic_binding A, 0 [symbolic]
+// CHECK:STDOUT:   %pattern_type.e25: type = pattern_type %X.type [concrete]
+// CHECK:STDOUT:   %Y.type: type = facet_type <@Y> [concrete]
+// CHECK:STDOUT:   %B: %Y.type = symbolic_binding B, 1 [symbolic]
+// CHECK:STDOUT:   %pattern_type.6e5: type = pattern_type %Y.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: imports {
+// CHECK:STDOUT:   %Main.Z = import_ref Main//a, Z, unloaded
+// CHECK:STDOUT:   %Main.Y: type = import_ref Main//a, Y, loaded [concrete = constants.%Y.type]
+// CHECK:STDOUT:   %Main.X: type = import_ref Main//a, X, loaded [concrete = constants.%X.type]
+// CHECK:STDOUT:   %Main.import_ref.cae = import_ref Main//a, loc9_14, unloaded
+// CHECK:STDOUT:   %Main.import_ref.581 = import_ref Main//a, loc5_13, unloaded
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [concrete] {
+// CHECK:STDOUT:     .Z = imports.%Main.Z
+// CHECK:STDOUT:     .Y = imports.%Main.Y
+// CHECK:STDOUT:     .X = imports.%Main.X
+// CHECK:STDOUT:     .F = %F.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %default.import.loc2_17.1 = import <none>
+// CHECK:STDOUT:   %default.import.loc2_17.2 = import <none>
+// CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {
+// CHECK:STDOUT:     %A.patt: %pattern_type.e25 = symbolic_binding_pattern A, 0 [concrete]
+// CHECK:STDOUT:     %B.patt: %pattern_type.6e5 = symbolic_binding_pattern B, 1 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %.loc4_10: type = splice_block %X.ref [concrete = constants.%X.type] {
+// CHECK:STDOUT:       %.Self.2: %type = symbolic_binding .Self [symbolic_self = constants.%.Self]
+// CHECK:STDOUT:       %X.ref: type = name_ref X, imports.%Main.X [concrete = constants.%X.type]
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:     %A.loc4_6.2: %X.type = symbolic_binding A, 0 [symbolic = %A.loc4_6.1 (constants.%A)]
+// CHECK:STDOUT:     %.loc4_17: type = splice_block %Y.ref [concrete = constants.%Y.type] {
+// CHECK:STDOUT:       %.Self.1: %type = symbolic_binding .Self [symbolic_self = constants.%.Self]
+// CHECK:STDOUT:       %Y.ref: type = name_ref Y, imports.%Main.Y [concrete = constants.%Y.type]
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:     %B.loc4_13.2: %Y.type = symbolic_binding B, 1 [symbolic = %B.loc4_13.1 (constants.%B)]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @Y [from "a.carbon"] {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = imports.%Main.import_ref.581
+// CHECK:STDOUT:   witness = ()
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: constraint @X [from "a.carbon"] {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = imports.%Main.import_ref.cae
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F(%A.loc4_6.2: %X.type, %B.loc4_13.2: %Y.type) {
+// CHECK:STDOUT:   %A.loc4_6.1: %X.type = symbolic_binding A, 0 [symbolic = %A.loc4_6.1 (constants.%A)]
+// CHECK:STDOUT:   %B.loc4_13.1: %Y.type = symbolic_binding B, 1 [symbolic = %B.loc4_13.1 (constants.%B)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn() {
+// CHECK:STDOUT:   !entry:
+// CHECK:STDOUT:     return
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F(constants.%A, constants.%B) {
+// CHECK:STDOUT:   %A.loc4_6.1 => constants.%A
+// CHECK:STDOUT:   %B.loc4_13.1 => constants.%B
+// CHECK:STDOUT: }
+// CHECK:STDOUT:

+ 17 - 0
toolchain/check/testdata/interface/incomplete.carbon

@@ -143,6 +143,7 @@ interface B {
 // CHECK:STDOUT:   %A.type: type = facet_type <@A> [concrete]
 // CHECK:STDOUT:   %B.type: type = facet_type <@B> [concrete]
 // CHECK:STDOUT:   %Self: %B.type = symbolic_binding Self, 0 [symbolic]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -158,6 +159,12 @@ interface B {
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @B {
 // CHECK:STDOUT:   %Self: %B.type = symbolic_binding Self, 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:   %B.require0.decl = require_decl @B.require0 [concrete] {
+// CHECK:STDOUT:     require %Self.as_type impls <@A>
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Self.as_type: type = facet_access_type @B.%Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:     %A.ref: type = name_ref A, file.%A.decl [concrete = constants.%A.type]
+// CHECK:STDOUT:   }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
@@ -165,6 +172,16 @@ interface B {
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: generic require @B.require0(@B.%Self: %B.type) {
+// CHECK:STDOUT:   %Self: %B.type = symbolic_binding Self, 0 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @B.require0(constants.%Self) {
+// CHECK:STDOUT:   %Self => constants.%Self
+// CHECK:STDOUT:   %Self.binding.as_type => constants.%Self.binding.as_type
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_incomplete_interface_in_where.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {

+ 213 - 6
toolchain/check/testdata/interface/require.carbon

@@ -272,8 +272,10 @@ interface Z(T:! type) {
 // CHECK:STDOUT: --- fail_todo_extend.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %Y.type: type = facet_type <@Y> [concrete]
 // CHECK:STDOUT:   %Z.type: type = facet_type <@Z> [concrete]
 // CHECK:STDOUT:   %Self.3b3: %Z.type = symbolic_binding Self, 0 [symbolic]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self.3b3 [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -285,6 +287,12 @@ interface Z(T:! type) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @Z {
 // CHECK:STDOUT:   %Self: %Z.type = symbolic_binding Self, 0 [symbolic = constants.%Self.3b3]
+// CHECK:STDOUT:   %Z.require0.decl = require_decl @Z.require0 [concrete] {
+// CHECK:STDOUT:     require %Self.as_type impls <@Y>
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Self.as_type: type = facet_access_type @Z.%Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:     %Y.ref: type = name_ref Y, file.%Y.decl [concrete = constants.%Y.type]
+// CHECK:STDOUT:   }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
@@ -293,11 +301,23 @@ interface Z(T:! type) {
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: generic require @Z.require0(@Z.%Self: %Z.type) {
+// CHECK:STDOUT:   %Self: %Z.type = symbolic_binding Self, 0 [symbolic = %Self (constants.%Self.3b3)]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @Z.require0(constants.%Self.3b3) {
+// CHECK:STDOUT:   %Self => constants.%Self.3b3
+// CHECK:STDOUT:   %Self.binding.as_type => constants.%Self.binding.as_type
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_todo_implicit_self_impls.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %Y.type: type = facet_type <@Y> [concrete]
 // CHECK:STDOUT:   %Z.type: type = facet_type <@Z> [concrete]
 // CHECK:STDOUT:   %Self.3b3: %Z.type = symbolic_binding Self, 0 [symbolic]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self.3b3 [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -309,6 +329,12 @@ interface Z(T:! type) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @Z {
 // CHECK:STDOUT:   %Self: %Z.type = symbolic_binding Self, 0 [symbolic = constants.%Self.3b3]
+// CHECK:STDOUT:   %Z.require0.decl = require_decl @Z.require0 [concrete] {
+// CHECK:STDOUT:     require %Self.as_type impls <@Y>
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Self.as_type: type = facet_access_type @Z.%Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:     %Y.ref: type = name_ref Y, file.%Y.decl [concrete = constants.%Y.type]
+// CHECK:STDOUT:   }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
@@ -316,11 +342,23 @@ interface Z(T:! type) {
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: generic require @Z.require0(@Z.%Self: %Z.type) {
+// CHECK:STDOUT:   %Self: %Z.type = symbolic_binding Self, 0 [symbolic = %Self (constants.%Self.3b3)]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @Z.require0(constants.%Self.3b3) {
+// CHECK:STDOUT:   %Self => constants.%Self.3b3
+// CHECK:STDOUT:   %Self.binding.as_type => constants.%Self.binding.as_type
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_todo_explicit_self_impls.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %Y.type: type = facet_type <@Y> [concrete]
 // CHECK:STDOUT:   %Z.type: type = facet_type <@Z> [concrete]
 // CHECK:STDOUT:   %Self.3b3: %Z.type = symbolic_binding Self, 0 [symbolic]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self.3b3 [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -332,6 +370,14 @@ interface Z(T:! type) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @Z {
 // CHECK:STDOUT:   %Self: %Z.type = symbolic_binding Self, 0 [symbolic = constants.%Self.3b3]
+// CHECK:STDOUT:   %Z.require0.decl = require_decl @Z.require0 [concrete] {
+// CHECK:STDOUT:     require %.loc9 impls <@Y>
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Self.ref: %Z.type = name_ref Self, @Z.%Self [symbolic = %Self (constants.%Self.3b3)]
+// CHECK:STDOUT:     %Self.as_type: type = facet_access_type %Self.ref [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:     %.loc9: type = converted %Self.ref, %Self.as_type [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:     %Y.ref: type = name_ref Y, file.%Y.decl [concrete = constants.%Y.type]
+// CHECK:STDOUT:   }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
@@ -339,11 +385,26 @@ interface Z(T:! type) {
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: generic require @Z.require0(@Z.%Self: %Z.type) {
+// CHECK:STDOUT:   %Self: %Z.type = symbolic_binding Self, 0 [symbolic = %Self (constants.%Self.3b3)]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @Z.require0(constants.%Self.3b3) {
+// CHECK:STDOUT:   %Self => constants.%Self.3b3
+// CHECK:STDOUT:   %Self.binding.as_type => constants.%Self.binding.as_type
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: --- explicit_self_specific_impls.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %Y.type: type = facet_type <@Y> [concrete]
+// CHECK:STDOUT:   %C.type: type = generic_class_type @C [concrete]
+// CHECK:STDOUT:   %C.generic: %C.type = struct_value () [concrete]
 // CHECK:STDOUT:   %Z.type: type = facet_type <@Z> [concrete]
 // CHECK:STDOUT:   %Self.3b3: %Z.type = symbolic_binding Self, 0 [symbolic]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self.3b3 [symbolic]
+// CHECK:STDOUT:   %C.b0f: type = class_type @C, @C(%Self.binding.as_type) [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -355,6 +416,16 @@ interface Z(T:! type) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @Z {
 // CHECK:STDOUT:   %Self: %Z.type = symbolic_binding Self, 0 [symbolic = constants.%Self.3b3]
+// CHECK:STDOUT:   %Z.require0.decl = require_decl @Z.require0 [concrete] {
+// CHECK:STDOUT:     require %C.loc9_17.1 impls <@Y>
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %C.ref: %C.type = name_ref C, file.%C.decl [concrete = constants.%C.generic]
+// CHECK:STDOUT:     %Self.ref: %Z.type = name_ref Self, @Z.%Self [symbolic = %Self (constants.%Self.3b3)]
+// CHECK:STDOUT:     %Self.as_type: type = facet_access_type %Self.ref [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:     %.loc9: type = converted %Self.ref, %Self.as_type [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:     %C.loc9_17.1: type = class_type @C, @C(constants.%Self.binding.as_type) [symbolic = %C.loc9_17.2 (constants.%C.b0f)]
+// CHECK:STDOUT:     %Y.ref: type = name_ref Y, file.%Y.decl [concrete = constants.%Y.type]
+// CHECK:STDOUT:   }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
@@ -363,11 +434,33 @@ interface Z(T:! type) {
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: generic require @Z.require0(@Z.%Self: %Z.type) {
+// CHECK:STDOUT:   %Self: %Z.type = symbolic_binding Self, 0 [symbolic = %Self (constants.%Self.3b3)]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:   %C.loc9_17.2: type = class_type @C, @C(%Self.binding.as_type) [symbolic = %C.loc9_17.2 (constants.%C.b0f)]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @Z.require0(constants.%Self.3b3) {
+// CHECK:STDOUT:   %Self => constants.%Self.3b3
+// CHECK:STDOUT:   %Self.binding.as_type => constants.%Self.binding.as_type
+// CHECK:STDOUT:   %C.loc9_17.2 => constants.%C.b0f
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: --- require_impls_where.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %Y.type: type = facet_type <@Y> [concrete]
+// CHECK:STDOUT:   %Y.assoc_type: type = assoc_entity_type @Y [concrete]
+// CHECK:STDOUT:   %assoc0: %Y.assoc_type = assoc_entity element0, @Y.%Y1 [concrete]
 // CHECK:STDOUT:   %Z.type: type = facet_type <@Z> [concrete]
 // CHECK:STDOUT:   %Self.3b3: %Z.type = symbolic_binding Self, 0 [symbolic]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self.3b3 [symbolic]
+// CHECK:STDOUT:   %.Self: %Y.type = symbolic_binding .Self [symbolic_self]
+// CHECK:STDOUT:   %empty_tuple.type: type = tuple_type () [concrete]
+// CHECK:STDOUT:   %.Self.binding.as_type: type = symbolic_binding_type .Self, %.Self [symbolic_self]
+// CHECK:STDOUT:   %Y.lookup_impl_witness: <witness> = lookup_impl_witness %.Self, @Y [symbolic_self]
+// CHECK:STDOUT:   %impl.elem0: type = impl_witness_access %Y.lookup_impl_witness, element0 [symbolic_self]
+// CHECK:STDOUT:   %Y_where.type: type = facet_type <@Y where %impl.elem0 = %empty_tuple.type> [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -379,6 +472,24 @@ interface Z(T:! type) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @Z {
 // CHECK:STDOUT:   %Self: %Z.type = symbolic_binding Self, 0 [symbolic = constants.%Self.3b3]
+// CHECK:STDOUT:   %Z.require0.decl = require_decl @Z.require0 [concrete] {
+// CHECK:STDOUT:     require %Self.as_type impls <@Y where constants.%impl.elem0 = constants.%empty_tuple.type>
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Self.as_type: type = facet_access_type @Z.%Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:     %Y.ref: type = name_ref Y, file.%Y.decl [concrete = constants.%Y.type]
+// CHECK:STDOUT:     <elided>
+// CHECK:STDOUT:     %.Self.ref: %Y.type = name_ref .Self, %.Self [symbolic_self = constants.%.Self]
+// CHECK:STDOUT:     %Y1.ref: %Y.assoc_type = name_ref Y1, @Y1.%assoc0 [concrete = constants.%assoc0]
+// CHECK:STDOUT:     %.Self.as_type: type = facet_access_type %.Self.ref [symbolic_self = constants.%.Self.binding.as_type]
+// CHECK:STDOUT:     %.loc7_25: type = converted %.Self.ref, %.Self.as_type [symbolic_self = constants.%.Self.binding.as_type]
+// CHECK:STDOUT:     %impl.elem0: type = impl_witness_access constants.%Y.lookup_impl_witness, element0 [symbolic_self = constants.%impl.elem0]
+// CHECK:STDOUT:     %.loc7_32.1: %empty_tuple.type = tuple_literal ()
+// CHECK:STDOUT:     %.loc7_32.2: type = converted %.loc7_32.1, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
+// CHECK:STDOUT:     %.loc7_19: type = where_expr %.Self [concrete = constants.%Y_where.type] {
+// CHECK:STDOUT:       requirement_base_facet_type constants.%Y.type
+// CHECK:STDOUT:       requirement_rewrite %impl.elem0, %.loc7_32.2
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:   }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
@@ -386,6 +497,16 @@ interface Z(T:! type) {
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: generic require @Z.require0(@Z.%Self: %Z.type) {
+// CHECK:STDOUT:   %Self: %Z.type = symbolic_binding Self, 0 [symbolic = %Self (constants.%Self.3b3)]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @Z.require0(constants.%Self.3b3) {
+// CHECK:STDOUT:   %Self => constants.%Self.3b3
+// CHECK:STDOUT:   %Self.binding.as_type => constants.%Self.binding.as_type
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: --- require_impls_self_specific.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
@@ -415,13 +536,22 @@ interface Z(T:! type) {
 // CHECK:STDOUT:   %T.loc4_13.1: type = symbolic_binding T, 0 [symbolic = %T.loc4_13.1 (constants.%T)]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !definition:
-// CHECK:STDOUT:   %Z.type.loc4: type = facet_type <@Z, @Z(%T.loc4_13.1)> [symbolic = %Z.type.loc4 (constants.%Z.type.4d7)]
-// CHECK:STDOUT:   %Self.loc4_23.2: @Z.%Z.type.loc4 (%Z.type.4d7) = symbolic_binding Self, 1 [symbolic = %Self.loc4_23.2 (constants.%Self)]
-// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 1, %Self.loc4_23.2 [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
-// CHECK:STDOUT:   %Z.type.loc5: type = facet_type <@Z, @Z(%Self.binding.as_type)> [symbolic = %Z.type.loc5 (constants.%Z.type.49d)]
+// CHECK:STDOUT:   %Z.type: type = facet_type <@Z, @Z(%T.loc4_13.1)> [symbolic = %Z.type (constants.%Z.type.4d7)]
+// CHECK:STDOUT:   %Self.loc4_23.2: @Z.%Z.type (%Z.type.4d7) = symbolic_binding Self, 1 [symbolic = %Self.loc4_23.2 (constants.%Self)]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   interface {
-// CHECK:STDOUT:     %Self.loc4_23.1: @Z.%Z.type.loc4 (%Z.type.4d7) = symbolic_binding Self, 1 [symbolic = %Self.loc4_23.2 (constants.%Self)]
+// CHECK:STDOUT:     %Self.loc4_23.1: @Z.%Z.type (%Z.type.4d7) = symbolic_binding Self, 1 [symbolic = %Self.loc4_23.2 (constants.%Self)]
+// CHECK:STDOUT:     %Z.require0.decl = require_decl @Z.require0 [concrete] {
+// CHECK:STDOUT:       require %T.ref impls <@Z, @Z(constants.%Self.binding.as_type)>
+// CHECK:STDOUT:     } {
+// CHECK:STDOUT:       %T.ref: type = name_ref T, @Z.%T.loc4_13.2 [symbolic = %T (constants.%T)]
+// CHECK:STDOUT:       %Z.ref: %Z.type.9fb = name_ref Z, file.%Z.decl [concrete = constants.%Z.generic]
+// CHECK:STDOUT:       %.loc5_21: @Z.require0.%Z.type.loc5_21 (%Z.type.4d7) = specific_constant @Z.%Self.loc4_23.1, @Z(constants.%T) [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:       %Self.ref: @Z.require0.%Z.type.loc5_21 (%Z.type.4d7) = name_ref Self, %.loc5_21 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:       %Self.as_type: type = facet_access_type %Self.ref [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:       %.loc5_25: type = converted %Self.ref, %Self.as_type [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:       %Z.type.loc5_25.1: type = facet_type <@Z, @Z(constants.%Self.binding.as_type)> [symbolic = %Z.type.loc5_25.2 (constants.%Z.type.49d)]
+// CHECK:STDOUT:     }
 // CHECK:STDOUT:
 // CHECK:STDOUT:   !members:
 // CHECK:STDOUT:     .Self = %Self.loc4_23.1
@@ -431,6 +561,14 @@ interface Z(T:! type) {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: generic require @Z.require0(@Z.%T.loc4_13.2: type, @Z.%Self.loc4_23.1: @Z.%Z.type (%Z.type.4d7)) {
+// CHECK:STDOUT:   %T: type = symbolic_binding T, 0 [symbolic = %T (constants.%T)]
+// CHECK:STDOUT:   %Z.type.loc5_21: type = facet_type <@Z, @Z(%T)> [symbolic = %Z.type.loc5_21 (constants.%Z.type.4d7)]
+// CHECK:STDOUT:   %Self: @Z.require0.%Z.type.loc5_21 (%Z.type.4d7) = symbolic_binding Self, 1 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 1, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:   %Z.type.loc5_25.2: type = facet_type <@Z, @Z(%Self.binding.as_type)> [symbolic = %Z.type.loc5_25.2 (constants.%Z.type.49d)]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: specific @Z(constants.%T) {
 // CHECK:STDOUT:   %T.loc4_13.1 => constants.%T
 // CHECK:STDOUT: }
@@ -439,11 +577,28 @@ interface Z(T:! type) {
 // CHECK:STDOUT:   %T.loc4_13.1 => constants.%Self.binding.as_type
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: specific @Z.require0(constants.%T, constants.%Self) {
+// CHECK:STDOUT:   %T => constants.%T
+// CHECK:STDOUT:   %Z.type.loc5_21 => constants.%Z.type.4d7
+// CHECK:STDOUT:   %Self => constants.%Self
+// CHECK:STDOUT:   %Self.binding.as_type => constants.%Self.binding.as_type
+// CHECK:STDOUT:   %Z.type.loc5_25.2 => constants.%Z.type.49d
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: --- require_self_in_requirement.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %Y.type: type = facet_type <@Y> [concrete]
+// CHECK:STDOUT:   %Y.assoc_type: type = assoc_entity_type @Y [concrete]
+// CHECK:STDOUT:   %assoc0: %Y.assoc_type = assoc_entity element0, @Y.%Y1 [concrete]
 // CHECK:STDOUT:   %Z.type: type = facet_type <@Z> [concrete]
 // CHECK:STDOUT:   %Self.3b3: %Z.type = symbolic_binding Self, 0 [symbolic]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self.3b3 [symbolic]
+// CHECK:STDOUT:   %.Self: %Y.type = symbolic_binding .Self [symbolic_self]
+// CHECK:STDOUT:   %.Self.binding.as_type: type = symbolic_binding_type .Self, %.Self [symbolic_self]
+// CHECK:STDOUT:   %Y.lookup_impl_witness: <witness> = lookup_impl_witness %.Self, @Y [symbolic_self]
+// CHECK:STDOUT:   %impl.elem0: type = impl_witness_access %Y.lookup_impl_witness, element0 [symbolic_self]
+// CHECK:STDOUT:   %Y_where.type: type = facet_type <@Y where %impl.elem0 = %Self.binding.as_type> [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -455,6 +610,25 @@ interface Z(T:! type) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @Z {
 // CHECK:STDOUT:   %Self: %Z.type = symbolic_binding Self, 0 [symbolic = constants.%Self.3b3]
+// CHECK:STDOUT:   %Z.require0.decl = require_decl @Z.require0 [concrete] {
+// CHECK:STDOUT:     require %Self.as_type.loc10_11 impls <@Y where constants.%impl.elem0 = constants.%Self.binding.as_type>
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Self.as_type.loc10_11: type = facet_access_type @Z.%Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:     %Y.ref: type = name_ref Y, file.%Y.decl [concrete = constants.%Y.type]
+// CHECK:STDOUT:     <elided>
+// CHECK:STDOUT:     %.Self.ref: %Y.type = name_ref .Self, %.Self [symbolic_self = constants.%.Self]
+// CHECK:STDOUT:     %Y1.ref: %Y.assoc_type = name_ref Y1, @Y1.%assoc0 [concrete = constants.%assoc0]
+// CHECK:STDOUT:     %.Self.as_type: type = facet_access_type %.Self.ref [symbolic_self = constants.%.Self.binding.as_type]
+// CHECK:STDOUT:     %.loc10_25: type = converted %.Self.ref, %.Self.as_type [symbolic_self = constants.%.Self.binding.as_type]
+// CHECK:STDOUT:     %impl.elem0: type = impl_witness_access constants.%Y.lookup_impl_witness, element0 [symbolic_self = constants.%impl.elem0]
+// CHECK:STDOUT:     %Self.ref: %Z.type = name_ref Self, @Z.%Self [symbolic = %Self (constants.%Self.3b3)]
+// CHECK:STDOUT:     %Self.as_type.loc10_31: type = facet_access_type %Self.ref [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:     %.loc10_31: type = converted %Self.ref, %Self.as_type.loc10_31 [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:     %.loc10_19: type = where_expr %.Self [symbolic = %Y_where.type (constants.%Y_where.type)] {
+// CHECK:STDOUT:       requirement_base_facet_type constants.%Y.type
+// CHECK:STDOUT:       requirement_rewrite %impl.elem0, %.loc10_31
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:   }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
@@ -462,6 +636,18 @@ interface Z(T:! type) {
 // CHECK:STDOUT:   witness = ()
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: generic require @Z.require0(@Z.%Self: %Z.type) {
+// CHECK:STDOUT:   %Self: %Z.type = symbolic_binding Self, 0 [symbolic = %Self (constants.%Self.3b3)]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:   %Y_where.type: type = facet_type <@Y where constants.%impl.elem0 = %Self.binding.as_type> [symbolic = %Y_where.type (constants.%Y_where.type)]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @Z.require0(constants.%Self.3b3) {
+// CHECK:STDOUT:   %Self => constants.%Self.3b3
+// CHECK:STDOUT:   %Self.binding.as_type => constants.%Self.binding.as_type
+// CHECK:STDOUT:   %Y_where.type => constants.%Y_where.type
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: --- require_same.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
@@ -492,10 +678,17 @@ interface Z(T:! type) {
 // CHECK:STDOUT: !definition:
 // CHECK:STDOUT:   %Z.type: type = facet_type <@Z, @Z(%T.loc8_13.1)> [symbolic = %Z.type (constants.%Z.type.4d7)]
 // CHECK:STDOUT:   %Self.loc8_23.2: @Z.%Z.type (%Z.type.4d7) = symbolic_binding Self, 1 [symbolic = %Self.loc8_23.2 (constants.%Self.c41)]
-// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 1, %Self.loc8_23.2 [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type.6a8)]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   interface {
 // CHECK:STDOUT:     %Self.loc8_23.1: @Z.%Z.type (%Z.type.4d7) = symbolic_binding Self, 1 [symbolic = %Self.loc8_23.2 (constants.%Self.c41)]
+// CHECK:STDOUT:     %Z.require1.decl = require_decl @Z.require1 [concrete] {
+// CHECK:STDOUT:       require %Self.as_type impls <@Z, @Z(constants.%T)>
+// CHECK:STDOUT:     } {
+// CHECK:STDOUT:       %Self.as_type: type = facet_access_type @Z.%Self.loc8_23.1 [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type.6a8)]
+// CHECK:STDOUT:       %Z.ref: %Z.type.9fb = name_ref Z, file.%Z.decl [concrete = constants.%Z.generic]
+// CHECK:STDOUT:       %T.ref: type = name_ref T, @Z.%T.loc8_13.2 [symbolic = %T (constants.%T)]
+// CHECK:STDOUT:       %Z.type.loc11_20: type = facet_type <@Z, @Z(constants.%T)> [symbolic = %Z.type.loc11_11 (constants.%Z.type.4d7)]
+// CHECK:STDOUT:     }
 // CHECK:STDOUT:
 // CHECK:STDOUT:   !members:
 // CHECK:STDOUT:     .Self = %Self.loc8_23.1
@@ -505,7 +698,21 @@ interface Z(T:! type) {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: generic require @Z.require1(@Z.%T.loc8_13.2: type, @Z.%Self.loc8_23.1: @Z.%Z.type (%Z.type.4d7)) {
+// CHECK:STDOUT:   %T: type = symbolic_binding T, 0 [symbolic = %T (constants.%T)]
+// CHECK:STDOUT:   %Z.type.loc11_11: type = facet_type <@Z, @Z(%T)> [symbolic = %Z.type.loc11_11 (constants.%Z.type.4d7)]
+// CHECK:STDOUT:   %Self: @Z.require1.%Z.type.loc11_11 (%Z.type.4d7) = symbolic_binding Self, 1 [symbolic = %Self (constants.%Self.c41)]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 1, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type.6a8)]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: specific @Z(constants.%T) {
 // CHECK:STDOUT:   %T.loc8_13.1 => constants.%T
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: specific @Z.require1(constants.%T, constants.%Self.c41) {
+// CHECK:STDOUT:   %T => constants.%T
+// CHECK:STDOUT:   %Z.type.loc11_11 => constants.%Z.type.4d7
+// CHECK:STDOUT:   %Self => constants.%Self.c41
+// CHECK:STDOUT:   %Self.binding.as_type => constants.%Self.binding.as_type.6a8
+// CHECK:STDOUT: }
+// CHECK:STDOUT:

+ 164 - 14
toolchain/check/testdata/named_constraint/require.carbon

@@ -300,8 +300,10 @@ constraint Z {
 // CHECK:STDOUT: --- fail_todo_extend.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %Y.type: type = facet_type <@Y> [concrete]
 // CHECK:STDOUT:   %Z.type: type = facet_type <@Z> [concrete]
 // CHECK:STDOUT:   %Self.861: %Z.type = symbolic_binding Self, 0 [symbolic]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self.861 [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -313,17 +315,35 @@ constraint Z {
 // CHECK:STDOUT:
 // CHECK:STDOUT: constraint @Z {
 // CHECK:STDOUT:   %Self: %Z.type = symbolic_binding Self, 0 [symbolic = constants.%Self.861]
+// CHECK:STDOUT:   %Z.require0.decl = require_decl @Z.require0 [concrete] {
+// CHECK:STDOUT:     require %Self.as_type impls <@Y>
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Self.as_type: type = facet_access_type @Z.%Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:     %Y.ref: type = name_ref Y, file.%Y.decl [concrete = constants.%Y.type]
+// CHECK:STDOUT:   }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
 // CHECK:STDOUT:   .Y = <poisoned>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: generic require @Z.require0(@Z.%Self: %Z.type) {
+// CHECK:STDOUT:   %Self: %Z.type = symbolic_binding Self, 0 [symbolic = %Self (constants.%Self.861)]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @Z.require0(constants.%Self.861) {
+// CHECK:STDOUT:   %Self => constants.%Self.861
+// CHECK:STDOUT:   %Self.binding.as_type => constants.%Self.binding.as_type
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_todo_implicit_self_impls.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %Y.type: type = facet_type <@Y> [concrete]
 // CHECK:STDOUT:   %Z.type: type = facet_type <@Z> [concrete]
 // CHECK:STDOUT:   %Self.861: %Z.type = symbolic_binding Self, 0 [symbolic]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self.861 [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -335,17 +355,35 @@ constraint Z {
 // CHECK:STDOUT:
 // CHECK:STDOUT: constraint @Z {
 // CHECK:STDOUT:   %Self: %Z.type = symbolic_binding Self, 0 [symbolic = constants.%Self.861]
+// CHECK:STDOUT:   %Z.require0.decl = require_decl @Z.require0 [concrete] {
+// CHECK:STDOUT:     require %Self.as_type impls <@Y>
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Self.as_type: type = facet_access_type @Z.%Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:     %Y.ref: type = name_ref Y, file.%Y.decl [concrete = constants.%Y.type]
+// CHECK:STDOUT:   }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
 // CHECK:STDOUT:   .Y = <poisoned>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: generic require @Z.require0(@Z.%Self: %Z.type) {
+// CHECK:STDOUT:   %Self: %Z.type = symbolic_binding Self, 0 [symbolic = %Self (constants.%Self.861)]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @Z.require0(constants.%Self.861) {
+// CHECK:STDOUT:   %Self => constants.%Self.861
+// CHECK:STDOUT:   %Self.binding.as_type => constants.%Self.binding.as_type
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_todo_explicit_self_impls.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %Y.type: type = facet_type <@Y> [concrete]
 // CHECK:STDOUT:   %Z.type: type = facet_type <@Z> [concrete]
 // CHECK:STDOUT:   %Self.861: %Z.type = symbolic_binding Self, 0 [symbolic]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self.861 [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -357,17 +395,40 @@ constraint Z {
 // CHECK:STDOUT:
 // CHECK:STDOUT: constraint @Z {
 // CHECK:STDOUT:   %Self: %Z.type = symbolic_binding Self, 0 [symbolic = constants.%Self.861]
+// CHECK:STDOUT:   %Z.require0.decl = require_decl @Z.require0 [concrete] {
+// CHECK:STDOUT:     require %.loc9 impls <@Y>
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Self.ref: %Z.type = name_ref Self, @Z.%Self [symbolic = %Self (constants.%Self.861)]
+// CHECK:STDOUT:     %Self.as_type: type = facet_access_type %Self.ref [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:     %.loc9: type = converted %Self.ref, %Self.as_type [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:     %Y.ref: type = name_ref Y, file.%Y.decl [concrete = constants.%Y.type]
+// CHECK:STDOUT:   }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
 // CHECK:STDOUT:   .Y = <poisoned>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: generic require @Z.require0(@Z.%Self: %Z.type) {
+// CHECK:STDOUT:   %Self: %Z.type = symbolic_binding Self, 0 [symbolic = %Self (constants.%Self.861)]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @Z.require0(constants.%Self.861) {
+// CHECK:STDOUT:   %Self => constants.%Self.861
+// CHECK:STDOUT:   %Self.binding.as_type => constants.%Self.binding.as_type
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: --- explicit_self_specific_impls.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %Y.type: type = facet_type <@Y> [concrete]
+// CHECK:STDOUT:   %C.type: type = generic_class_type @C [concrete]
+// CHECK:STDOUT:   %C.generic: %C.type = struct_value () [concrete]
 // CHECK:STDOUT:   %Z.type: type = facet_type <@Z> [concrete]
 // CHECK:STDOUT:   %Self.861: %Z.type = symbolic_binding Self, 0 [symbolic]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self.861 [symbolic]
+// CHECK:STDOUT:   %C.42a: type = class_type @C, @C(%Self.binding.as_type) [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -379,6 +440,16 @@ constraint Z {
 // CHECK:STDOUT:
 // CHECK:STDOUT: constraint @Z {
 // CHECK:STDOUT:   %Self: %Z.type = symbolic_binding Self, 0 [symbolic = constants.%Self.861]
+// CHECK:STDOUT:   %Z.require0.decl = require_decl @Z.require0 [concrete] {
+// CHECK:STDOUT:     require %C.loc9_17.1 impls <@Y>
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %C.ref: %C.type = name_ref C, file.%C.decl [concrete = constants.%C.generic]
+// CHECK:STDOUT:     %Self.ref: %Z.type = name_ref Self, @Z.%Self [symbolic = %Self (constants.%Self.861)]
+// CHECK:STDOUT:     %Self.as_type: type = facet_access_type %Self.ref [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:     %.loc9: type = converted %Self.ref, %Self.as_type [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:     %C.loc9_17.1: type = class_type @C, @C(constants.%Self.binding.as_type) [symbolic = %C.loc9_17.2 (constants.%C.42a)]
+// CHECK:STDOUT:     %Y.ref: type = name_ref Y, file.%Y.decl [concrete = constants.%Y.type]
+// CHECK:STDOUT:   }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
@@ -386,11 +457,33 @@ constraint Z {
 // CHECK:STDOUT:   .Y = <poisoned>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: generic require @Z.require0(@Z.%Self: %Z.type) {
+// CHECK:STDOUT:   %Self: %Z.type = symbolic_binding Self, 0 [symbolic = %Self (constants.%Self.861)]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:   %C.loc9_17.2: type = class_type @C, @C(%Self.binding.as_type) [symbolic = %C.loc9_17.2 (constants.%C.42a)]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @Z.require0(constants.%Self.861) {
+// CHECK:STDOUT:   %Self => constants.%Self.861
+// CHECK:STDOUT:   %Self.binding.as_type => constants.%Self.binding.as_type
+// CHECK:STDOUT:   %C.loc9_17.2 => constants.%C.42a
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: --- require_impls_where.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %Y.type: type = facet_type <@Y> [concrete]
+// CHECK:STDOUT:   %Y.assoc_type: type = assoc_entity_type @Y [concrete]
+// CHECK:STDOUT:   %assoc0: %Y.assoc_type = assoc_entity element0, @Y.%Y1 [concrete]
 // CHECK:STDOUT:   %Z.type: type = facet_type <@Z> [concrete]
 // CHECK:STDOUT:   %Self.861: %Z.type = symbolic_binding Self, 0 [symbolic]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self.861 [symbolic]
+// CHECK:STDOUT:   %.Self: %Y.type = symbolic_binding .Self [symbolic_self]
+// CHECK:STDOUT:   %empty_tuple.type: type = tuple_type () [concrete]
+// CHECK:STDOUT:   %.Self.binding.as_type: type = symbolic_binding_type .Self, %.Self [symbolic_self]
+// CHECK:STDOUT:   %Y.lookup_impl_witness: <witness> = lookup_impl_witness %.Self, @Y [symbolic_self]
+// CHECK:STDOUT:   %impl.elem0: type = impl_witness_access %Y.lookup_impl_witness, element0 [symbolic_self]
+// CHECK:STDOUT:   %Y_where.type: type = facet_type <@Y where %impl.elem0 = %empty_tuple.type> [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -402,12 +495,40 @@ constraint Z {
 // CHECK:STDOUT:
 // CHECK:STDOUT: constraint @Z {
 // CHECK:STDOUT:   %Self: %Z.type = symbolic_binding Self, 0 [symbolic = constants.%Self.861]
+// CHECK:STDOUT:   %Z.require0.decl = require_decl @Z.require0 [concrete] {
+// CHECK:STDOUT:     require %Self.as_type impls <@Y where constants.%impl.elem0 = constants.%empty_tuple.type>
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Self.as_type: type = facet_access_type @Z.%Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:     %Y.ref: type = name_ref Y, file.%Y.decl [concrete = constants.%Y.type]
+// CHECK:STDOUT:     <elided>
+// CHECK:STDOUT:     %.Self.ref: %Y.type = name_ref .Self, %.Self [symbolic_self = constants.%.Self]
+// CHECK:STDOUT:     %Y1.ref: %Y.assoc_type = name_ref Y1, @Y1.%assoc0 [concrete = constants.%assoc0]
+// CHECK:STDOUT:     %.Self.as_type: type = facet_access_type %.Self.ref [symbolic_self = constants.%.Self.binding.as_type]
+// CHECK:STDOUT:     %.loc7_25: type = converted %.Self.ref, %.Self.as_type [symbolic_self = constants.%.Self.binding.as_type]
+// CHECK:STDOUT:     %impl.elem0: type = impl_witness_access constants.%Y.lookup_impl_witness, element0 [symbolic_self = constants.%impl.elem0]
+// CHECK:STDOUT:     %.loc7_32.1: %empty_tuple.type = tuple_literal ()
+// CHECK:STDOUT:     %.loc7_32.2: type = converted %.loc7_32.1, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
+// CHECK:STDOUT:     %.loc7_19: type = where_expr %.Self [concrete = constants.%Y_where.type] {
+// CHECK:STDOUT:       requirement_base_facet_type constants.%Y.type
+// CHECK:STDOUT:       requirement_rewrite %impl.elem0, %.loc7_32.2
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:   }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
 // CHECK:STDOUT:   .Y = <poisoned>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: generic require @Z.require0(@Z.%Self: %Z.type) {
+// CHECK:STDOUT:   %Self: %Z.type = symbolic_binding Self, 0 [symbolic = %Self (constants.%Self.861)]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @Z.require0(constants.%Self.861) {
+// CHECK:STDOUT:   %Self => constants.%Self.861
+// CHECK:STDOUT:   %Self.binding.as_type => constants.%Self.binding.as_type
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_require_impls_incomplete_constraint.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
@@ -462,7 +583,6 @@ constraint Z {
 // CHECK:STDOUT:   %Z.type.b8d23b.1: type = facet_type <@Z, @Z(%T)> [symbolic]
 // CHECK:STDOUT:   %Self: %Z.type.b8d23b.1 = symbolic_binding Self, 1 [symbolic]
 // CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 1, %Self [symbolic]
-// CHECK:STDOUT:   %Z.type.b8d23b.2: type = facet_type <@Z, @Z(%Self.binding.as_type)> [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -481,13 +601,11 @@ constraint Z {
 // CHECK:STDOUT:   %T.loc4_14.1: type = symbolic_binding T, 0 [symbolic = %T.loc4_14.1 (constants.%T)]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !definition:
-// CHECK:STDOUT:   %type.loc4: type = facet_type <type> [symbolic = %type.loc4 (constants.%Z.type.b8d23b.1)]
-// CHECK:STDOUT:   %Self.loc4_24.2: @Z.%type.loc4 (%Z.type.b8d23b.1) = symbolic_binding Self, 1 [symbolic = %Self.loc4_24.2 (constants.%Self)]
-// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 1, %Self.loc4_24.2 [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
-// CHECK:STDOUT:   %type.loc12: type = facet_type <type> [symbolic = %type.loc12 (constants.%Z.type.b8d23b.2)]
+// CHECK:STDOUT:   %type: type = facet_type <type> [symbolic = %type (constants.%Z.type.b8d23b.1)]
+// CHECK:STDOUT:   %Self.loc4_24.2: @Z.%type (%Z.type.b8d23b.1) = symbolic_binding Self, 1 [symbolic = %Self.loc4_24.2 (constants.%Self)]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   constraint {
-// CHECK:STDOUT:     %Self.loc4_24.1: @Z.%type.loc4 (%Z.type.b8d23b.1) = symbolic_binding Self, 1 [symbolic = %Self.loc4_24.2 (constants.%Self)]
+// CHECK:STDOUT:     %Self.loc4_24.1: @Z.%type (%Z.type.b8d23b.1) = symbolic_binding Self, 1 [symbolic = %Self.loc4_24.2 (constants.%Self)]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   !members:
 // CHECK:STDOUT:     .Self = %Self.loc4_24.1
@@ -507,18 +625,12 @@ constraint Z {
 // CHECK:STDOUT: --- fail_require_impls_without_self.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
-// CHECK:STDOUT:   %Y.type: type = facet_type <@Y> [concrete]
 // CHECK:STDOUT:   %T: type = symbolic_binding T, 0 [symbolic]
 // CHECK:STDOUT:   %pattern_type: type = pattern_type type [concrete]
 // CHECK:STDOUT:   %Z.type.82a: type = generic_named_constaint_type @Z [concrete]
 // CHECK:STDOUT:   %empty_struct: %Z.type.82a = struct_value () [concrete]
 // CHECK:STDOUT:   %Z.type.b8d: type = facet_type <@Z, @Z(%T)> [symbolic]
 // CHECK:STDOUT:   %Self.aa1: %Z.type.b8d = symbolic_binding Self, 1 [symbolic]
-// CHECK:STDOUT:   %.Self.a96: %Y.type = symbolic_binding .Self [symbolic_self]
-// CHECK:STDOUT:   %Y.lookup_impl_witness: <witness> = lookup_impl_witness %.Self.a96, @Y [symbolic_self]
-// CHECK:STDOUT:   %impl.elem0: type = impl_witness_access %Y.lookup_impl_witness, element0 [symbolic_self]
-// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 1, %Self.aa1 [symbolic]
-// CHECK:STDOUT:   %Y_where.type: type = facet_type <@Y where %impl.elem0 = %Self.binding.as_type> [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -539,8 +651,6 @@ constraint Z {
 // CHECK:STDOUT: !definition:
 // CHECK:STDOUT:   %type: type = facet_type <type> [symbolic = %type (constants.%Z.type.b8d)]
 // CHECK:STDOUT:   %Self.loc8_24.2: @Z.%type (%Z.type.b8d) = symbolic_binding Self, 1 [symbolic = %Self.loc8_24.2 (constants.%Self.aa1)]
-// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 1, %Self.loc8_24.2 [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
-// CHECK:STDOUT:   %Y_where.type: type = facet_type <@Y where constants.%impl.elem0 = %Self.binding.as_type> [symbolic = %Y_where.type (constants.%Y_where.type)]
 // CHECK:STDOUT:
 // CHECK:STDOUT:   constraint {
 // CHECK:STDOUT:     %Self.loc8_24.1: @Z.%type (%Z.type.b8d) = symbolic_binding Self, 1 [symbolic = %Self.loc8_24.2 (constants.%Self.aa1)]
@@ -559,8 +669,17 @@ constraint Z {
 // CHECK:STDOUT: --- require_self_in_requirement.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %Y.type: type = facet_type <@Y> [concrete]
+// CHECK:STDOUT:   %Y.assoc_type: type = assoc_entity_type @Y [concrete]
+// CHECK:STDOUT:   %assoc0: %Y.assoc_type = assoc_entity element0, @Y.%Y1 [concrete]
 // CHECK:STDOUT:   %Z.type: type = facet_type <@Z> [concrete]
 // CHECK:STDOUT:   %Self.861: %Z.type = symbolic_binding Self, 0 [symbolic]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self.861 [symbolic]
+// CHECK:STDOUT:   %.Self: %Y.type = symbolic_binding .Self [symbolic_self]
+// CHECK:STDOUT:   %.Self.binding.as_type: type = symbolic_binding_type .Self, %.Self [symbolic_self]
+// CHECK:STDOUT:   %Y.lookup_impl_witness: <witness> = lookup_impl_witness %.Self, @Y [symbolic_self]
+// CHECK:STDOUT:   %impl.elem0: type = impl_witness_access %Y.lookup_impl_witness, element0 [symbolic_self]
+// CHECK:STDOUT:   %Y_where.type: type = facet_type <@Y where %impl.elem0 = %Self.binding.as_type> [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -572,9 +691,40 @@ constraint Z {
 // CHECK:STDOUT:
 // CHECK:STDOUT: constraint @Z {
 // CHECK:STDOUT:   %Self: %Z.type = symbolic_binding Self, 0 [symbolic = constants.%Self.861]
+// CHECK:STDOUT:   %Z.require0.decl = require_decl @Z.require0 [concrete] {
+// CHECK:STDOUT:     require %Self.as_type.loc10_11 impls <@Y where constants.%impl.elem0 = constants.%Self.binding.as_type>
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Self.as_type.loc10_11: type = facet_access_type @Z.%Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:     %Y.ref: type = name_ref Y, file.%Y.decl [concrete = constants.%Y.type]
+// CHECK:STDOUT:     <elided>
+// CHECK:STDOUT:     %.Self.ref: %Y.type = name_ref .Self, %.Self [symbolic_self = constants.%.Self]
+// CHECK:STDOUT:     %Y1.ref: %Y.assoc_type = name_ref Y1, @Y1.%assoc0 [concrete = constants.%assoc0]
+// CHECK:STDOUT:     %.Self.as_type: type = facet_access_type %.Self.ref [symbolic_self = constants.%.Self.binding.as_type]
+// CHECK:STDOUT:     %.loc10_25: type = converted %.Self.ref, %.Self.as_type [symbolic_self = constants.%.Self.binding.as_type]
+// CHECK:STDOUT:     %impl.elem0: type = impl_witness_access constants.%Y.lookup_impl_witness, element0 [symbolic_self = constants.%impl.elem0]
+// CHECK:STDOUT:     %Self.ref: %Z.type = name_ref Self, @Z.%Self [symbolic = %Self (constants.%Self.861)]
+// CHECK:STDOUT:     %Self.as_type.loc10_31: type = facet_access_type %Self.ref [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:     %.loc10_31: type = converted %Self.ref, %Self.as_type.loc10_31 [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:     %.loc10_19: type = where_expr %.Self [symbolic = %Y_where.type (constants.%Y_where.type)] {
+// CHECK:STDOUT:       requirement_base_facet_type constants.%Y.type
+// CHECK:STDOUT:       requirement_rewrite %impl.elem0, %.loc10_31
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:   }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
 // CHECK:STDOUT:   .Y = <poisoned>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: generic require @Z.require0(@Z.%Self: %Z.type) {
+// CHECK:STDOUT:   %Self: %Z.type = symbolic_binding Self, 0 [symbolic = %Self (constants.%Self.861)]
+// CHECK:STDOUT:   %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
+// CHECK:STDOUT:   %Y_where.type: type = facet_type <@Y where constants.%impl.elem0 = %Self.binding.as_type> [symbolic = %Y_where.type (constants.%Y_where.type)]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @Z.require0(constants.%Self.861) {
+// CHECK:STDOUT:   %Self => constants.%Self.861
+// CHECK:STDOUT:   %Self.binding.as_type => constants.%Self.binding.as_type
+// CHECK:STDOUT:   %Y_where.type => constants.%Y_where.type
+// CHECK:STDOUT: }
+// CHECK:STDOUT:

+ 1 - 0
toolchain/sem_ir/BUILD

@@ -106,6 +106,7 @@ cc_library(
         "name_scope.h",
         "named_constraint.h",
         "pattern.h",
+        "require_impls.h",
         "struct_type_field.h",
         "type.h",
         "type_info.h",

+ 1 - 0
toolchain/sem_ir/expr_info.cpp

@@ -35,6 +35,7 @@ auto GetExprCategory(const File& file, InstId inst_id) -> ExprCategory {
       case OutParamPattern::Kind:
       case RefBindingPattern::Kind:
       case RefParamPattern::Kind:
+      case RequireImplsDecl::Kind:
       case RequirementBaseFacetType::Kind:
       case RequirementEquivalent::Kind:
       case RequirementImpls::Kind:

+ 8 - 0
toolchain/sem_ir/file.h

@@ -36,6 +36,7 @@
 #include "toolchain/sem_ir/name.h"
 #include "toolchain/sem_ir/name_scope.h"
 #include "toolchain/sem_ir/named_constraint.h"
+#include "toolchain/sem_ir/require_impls.h"
 #include "toolchain/sem_ir/singleton_insts.h"
 #include "toolchain/sem_ir/specific_interface.h"
 #include "toolchain/sem_ir/struct_type_field.h"
@@ -178,6 +179,10 @@ class File : public Printable<File> {
   auto named_constraints() const -> const NamedConstraintStore& {
     return named_constraints_;
   }
+  auto require_impls() -> RequireImplsStore& { return require_impls_; }
+  auto require_impls() const -> const RequireImplsStore& {
+    return require_impls_;
+  }
   auto associated_constants() -> AssociatedConstantStore& {
     return associated_constants_;
   }
@@ -329,6 +334,9 @@ class File : public Printable<File> {
   // Storage for named constraints.
   NamedConstraintStore named_constraints_;
 
+  // Storage for interface requirements.
+  RequireImplsStore require_impls_;
+
   // Storage for associated constants.
   AssociatedConstantStore associated_constants_;
 

+ 67 - 4
toolchain/sem_ir/formatter.cpp

@@ -85,6 +85,10 @@ auto Formatter::Format() -> void {
     FormatNamedConstraint(id, constraint);
   }
 
+  for (const auto& [id, require] : sem_ir_->require_impls().enumerate()) {
+    FormatRequireImpls(id, require);
+  }
+
   for (const auto& [id, assoc_const] :
        sem_ir_->associated_constants().enumerate()) {
     FormatAssociatedConstant(id, assoc_const);
@@ -341,6 +345,7 @@ auto Formatter::FormatClass(ClassId id, const Class& class_info) -> void {
     return;
   }
 
+  PrepareToFormatDecl(class_info.first_owning_decl_id);
   FormatEntityStart("class", class_info, id);
 
   llvm::SaveAndRestore class_scope(scope_, inst_namer_.GetScopeFor(id));
@@ -393,6 +398,7 @@ auto Formatter::FormatInterface(InterfaceId id, const Interface& interface_info)
     return;
   }
 
+  PrepareToFormatDecl(interface_info.first_owning_decl_id);
   FormatEntityStart("interface", interface_info, id);
 
   llvm::SaveAndRestore interface_scope(scope_, inst_namer_.GetScopeFor(id));
@@ -429,6 +435,7 @@ auto Formatter::FormatNamedConstraint(NamedConstraintId id,
     return;
   }
 
+  PrepareToFormatDecl(constraint_info.first_owning_decl_id);
   FormatEntityStart("constraint", constraint_info, id);
 
   llvm::SaveAndRestore constraint_scope(scope_, inst_namer_.GetScopeFor(id));
@@ -455,6 +462,17 @@ auto Formatter::FormatNamedConstraint(NamedConstraintId id,
   FormatEntityEnd(constraint_info.generic_id);
 }
 
+auto Formatter::FormatRequireImpls(RequireImplsId /*id*/,
+                                   const RequireImpls& require) -> void {
+  if (!ShouldFormatEntity(require.decl_id)) {
+    return;
+  }
+
+  PrepareToFormatDecl(require.decl_id);
+  FormatGenericStart("require", require.generic_id);
+  FormatGenericEnd();
+}
+
 auto Formatter::FormatAssociatedConstant(AssociatedConstantId id,
                                          const AssociatedConstant& assoc_const)
     -> void {
@@ -462,8 +480,8 @@ auto Formatter::FormatAssociatedConstant(AssociatedConstantId id,
     return;
   }
 
-  FormatEntityStart("assoc_const", assoc_const.decl_id, assoc_const.generic_id,
-                    id);
+  PrepareToFormatDecl(assoc_const.decl_id);
+  FormatEntityStart("assoc_const", assoc_const.generic_id, id);
 
   llvm::SaveAndRestore assoc_const_scope(scope_, inst_namer_.GetScopeFor(id));
 
@@ -485,6 +503,7 @@ auto Formatter::FormatImpl(ImplId id, const Impl& impl_info) -> void {
     return;
   }
 
+  PrepareToFormatDecl(impl_info.first_owning_decl_id);
   FormatEntityStart("impl", impl_info, id);
 
   llvm::SaveAndRestore impl_scope(scope_, inst_namer_.GetScopeFor(id));
@@ -544,6 +563,7 @@ auto Formatter::FormatFunction(FunctionId id, const Function& fn) -> void {
     function_start += "extern ";
   }
   function_start += "fn";
+  PrepareToFormatDecl(fn.first_owning_decl_id);
   FormatEntityStart(function_start, fn, id);
 
   llvm::SaveAndRestore function_scope(scope_, inst_namer_.GetScopeFor(id));
@@ -652,6 +672,23 @@ auto Formatter::FormatSpecific(SpecificId id, const Specific& specific)
   out_ << "\n";
 }
 
+auto Formatter::PrepareToFormatDecl(InstId first_owning_decl_id) -> void {
+  // If this decl was imported from a different IR, annotate the name of
+  // that IR in the output before the `{` or `;`.
+  if (first_owning_decl_id.has_value()) {
+    auto import_ir_inst_id =
+        sem_ir_->insts().GetImportSource(first_owning_decl_id);
+    if (import_ir_inst_id.has_value()) {
+      auto import_ir_id =
+          sem_ir_->import_ir_insts().Get(import_ir_inst_id).ir_id();
+      if (const auto* import_file =
+              sem_ir_->import_irs().Get(import_ir_id).sem_ir) {
+        pending_imported_from_ = import_file->filename();
+      }
+    }
+  }
+}
+
 auto Formatter::FormatGenericStart(llvm::StringRef entity_kind,
                                    GenericId generic_id) -> void {
   const auto& generic = sem_ir_->generics().Get(generic_id);
@@ -677,11 +714,15 @@ auto Formatter::FormatGenericStart(llvm::StringRef entity_kind,
 
 auto Formatter::FormatEntityEnd(GenericId generic_id) -> void {
   if (generic_id.has_value()) {
-    CloseBrace();
-    out_ << '\n';
+    FormatGenericEnd();
   }
 }
 
+auto Formatter::FormatGenericEnd() -> void {
+  CloseBrace();
+  out_ << '\n';
+}
+
 auto Formatter::FormatParamList(InstBlockId params_id, bool has_return_slot)
     -> void {
   if (!params_id.has_value()) {
@@ -1140,6 +1181,28 @@ auto Formatter::FormatInstRhs(Inst inst) -> void {
       return;
     }
 
+    case CARBON_KIND(RequireImplsDecl decl): {
+      FormatArgs(decl.require_impls_id);
+
+      const auto& require = sem_ir_->require_impls().Get(decl.require_impls_id);
+
+      llvm::SaveAndRestore scope(
+          scope_, inst_namer_.GetScopeFor(decl.require_impls_id));
+
+      out_ << ' ';
+      OpenBrace();
+      Indent();
+      out_ << "require ";
+      FormatArg(require.self_id);
+      out_ << " impls ";
+      FormatArg(require.facet_type_id);
+      out_ << "\n";
+      CloseBrace();
+
+      FormatTrailingBlock(decl.decl_block_id);
+      return;
+    }
+
     case CARBON_KIND(ReturnExpr ret): {
       FormatArgs(ret.expr_id);
       if (ret.dest_id.has_value()) {

+ 15 - 20
toolchain/sem_ir/formatter.h

@@ -162,6 +162,10 @@ class Formatter {
   auto FormatNamedConstraint(NamedConstraintId id,
                              const NamedConstraint& constraint_info) -> void;
 
+  // Formats a full require declaration.
+  auto FormatRequireImpls(RequireImplsId id, const RequireImpls& require)
+      -> void;
+
   // Formats an associated constant entity.
   auto FormatAssociatedConstant(AssociatedConstantId id,
                                 const AssociatedConstant& assoc_const) -> void;
@@ -184,10 +188,13 @@ class Formatter {
   auto FormatGenericStart(llvm::StringRef entity_kind, GenericId generic_id)
       -> void;
 
+  // Before formatting a decl (typically an Entity), collect import information
+  // (if there is any) needed to format it.
+  auto PrepareToFormatDecl(InstId first_owning_decl_id) -> void;
+
   // Provides common formatting for entities, paired with FormatEntityEnd.
   template <typename IdT>
-  auto FormatEntityStart(llvm::StringRef entity_kind,
-                         InstId first_owning_decl_id, GenericId generic_id,
+  auto FormatEntityStart(llvm::StringRef entity_kind, GenericId generic_id,
                          IdT entity_id) -> void;
 
   template <typename IdT>
@@ -198,6 +205,11 @@ class Formatter {
   // Provides common formatting for entities, paired with FormatEntityStart.
   auto FormatEntityEnd(GenericId generic_id) -> void;
 
+  // Provides common formatting for generics, paired with FormatGenericStart.
+  // Normally this is just called from FormatEntityEnd, as most generics are
+  // entities.
+  auto FormatGenericEnd() -> void;
+
   // Formats parameters, eliding them completely if they're empty. Wraps input
   // parameters in parentheses. Formats output parameter as a return type.
   auto FormatParamList(InstBlockId params_id, bool has_return_slot = false)
@@ -398,23 +410,7 @@ class Formatter {
 
 template <typename IdT>
 auto Formatter::FormatEntityStart(llvm::StringRef entity_kind,
-                                  InstId first_owning_decl_id,
                                   GenericId generic_id, IdT entity_id) -> void {
-  // If this entity was imported from a different IR, annotate the name of
-  // that IR in the output before the `{` or `;`.
-  if (first_owning_decl_id.has_value()) {
-    auto import_ir_inst_id =
-        sem_ir_->insts().GetImportSource(first_owning_decl_id);
-    if (import_ir_inst_id.has_value()) {
-      auto import_ir_id =
-          sem_ir_->import_ir_insts().Get(import_ir_inst_id).ir_id();
-      if (const auto* import_file =
-              sem_ir_->import_irs().Get(import_ir_id).sem_ir) {
-        pending_imported_from_ = import_file->filename();
-      }
-    }
-  }
-
   if (generic_id.has_value()) {
     FormatGenericStart(entity_kind, generic_id);
   }
@@ -436,8 +432,7 @@ template <typename IdT>
 auto Formatter::FormatEntityStart(llvm::StringRef entity_kind,
                                   const EntityWithParamsBase& entity,
                                   IdT entity_id) -> void {
-  FormatEntityStart(entity_kind, entity.first_owning_decl_id, entity.generic_id,
-                    entity_id);
+  FormatEntityStart(entity_kind, entity.generic_id, entity_id);
 }
 
 template <typename... Types>

+ 1 - 0
toolchain/sem_ir/id_kind.h

@@ -61,6 +61,7 @@ using IdKind = TypeEnum<
     NameId,
     NameScopeId,
     NamedConstraintId,
+    RequireImplsId,
     SpecificId,
     SpecificInterfaceId,
     StructTypeFieldsId,

+ 7 - 0
toolchain/sem_ir/ids.h

@@ -922,6 +922,13 @@ struct ImportIRInstId : public IdBase<ImportIRInstId> {
   }
 };
 
+// The ID of a `RequireImpls`.
+struct RequireImplsId : public IdBase<RequireImplsId> {
+  static constexpr llvm::StringLiteral Label = "require_impls";
+
+  using IdBase::IdBase;
+};
+
 // A SemIR location used as the location of instructions. This contains either a
 // InstId, NodeId, ImportIRInstId, or None. The intent is that any of these can
 // indicate the source of an instruction, and also be used to associate a line

+ 10 - 0
toolchain/sem_ir/inst_fingerprinter.cpp

@@ -243,6 +243,16 @@ struct Worklist {
     AddEntity(sem_ir->named_constraints().Get(named_constraint_id));
   }
 
+  auto Add(RequireImplsId require_id) -> void {
+    if (!require_id.has_value()) {
+      AddInvalid();
+      return;
+    }
+    const auto& require = sem_ir->require_impls().Get(require_id);
+    Add(require.self_id);
+    Add(require.facet_type_id);
+  }
+
   auto Add(AssociatedConstantId assoc_const_id) -> void {
     AddEntity<AssociatedConstant>(
         sem_ir->associated_constants().Get(assoc_const_id));

+ 1 - 0
toolchain/sem_ir/inst_kind.def

@@ -111,6 +111,7 @@ CARBON_SEM_IR_INST_KIND(RefParam)
 CARBON_SEM_IR_INST_KIND(RefParamPattern)
 CARBON_SEM_IR_INST_KIND(RefineTypeAction)
 CARBON_SEM_IR_INST_KIND(RequireCompleteType)
+CARBON_SEM_IR_INST_KIND(RequireImplsDecl)
 CARBON_SEM_IR_INST_KIND(RequirementBaseFacetType)
 CARBON_SEM_IR_INST_KIND(RequirementEquivalent)
 CARBON_SEM_IR_INST_KIND(RequirementImpls)

+ 40 - 0
toolchain/sem_ir/inst_namer.cpp

@@ -59,6 +59,16 @@ class InstNamer::NamingContext {
   auto AddWitnessTableName(InstId witness_table_inst_id, std::string name)
       -> void;
 
+  auto AddBlockLabel(ScopeId scope_id, InstBlockId block_id, std::string name,
+                     LocId loc_id) -> void {
+    inst_namer_->AddBlockLabel(scope_id, block_id, name, loc_id);
+  }
+
+  // Pushes all instructions in a generic, by ID.
+  auto PushGeneric(ScopeId scope_id, GenericId generic_id) -> void {
+    inst_namer_->PushGeneric(scope_id, generic_id);
+  }
+
   // Pushes all instructions in a block, by ID.
   auto PushBlockId(ScopeId scope_id, InstBlockId block_id) -> void {
     inst_namer_->PushBlockId(scope_id, block_id);
@@ -159,6 +169,10 @@ auto InstNamer::GetScopeIdOffset(ScopeIdTypeEnum id_enum) const -> int {
       [[fallthrough]];
     case ScopeIdTypeEnum::For<NamedConstraintId>:
 
+      offset += sem_ir_->require_impls().size();
+      [[fallthrough]];
+    case ScopeIdTypeEnum::For<RequireImplsId>:
+
       offset += sem_ir_->specific_interfaces().size();
       [[fallthrough]];
     case ScopeIdTypeEnum::For<SpecificInterfaceId>:
@@ -590,6 +604,26 @@ auto InstNamer::PushEntity(FunctionId function_id, ScopeId scope_id,
   PushBlockId(scope_id, fn.call_params_id);
 }
 
+auto InstNamer::PushEntity(RequireImplsId require_impls_id, ScopeId scope_id,
+                           Scope& scope) -> void {
+  const auto& require = sem_ir_->require_impls().Get(require_impls_id);
+  LocId require_loc(require.decl_id);
+
+  auto scope_prefix = GetNameForParentNameScope(require.parent_scope_id);
+
+  scope.name = globals_.AllocateName(
+      *this, require_loc,
+      // TODO: Include the Interface being required if there's only one, instead
+      // of the index.
+      llvm::formatv("{0}{1}require{2}", scope_prefix,
+                    scope_prefix.empty() ? "" : ".", require_impls_id.index));
+
+  AddBlockLabel(scope_id, require.body_block_id, "require", require_loc);
+
+  // Push blocks in reverse order.
+  PushGeneric(scope_id, require.generic_id);
+}
+
 auto InstNamer::PushEntity(CppOverloadSetId cpp_overload_set_id,
                            ScopeId /*scope_id*/, Scope& scope) -> void {
   const CppOverloadSet& overload_set =
@@ -1136,6 +1170,12 @@ auto InstNamer::NamingContext::NameInst() -> void {
       AddInstName("require_complete");
       return;
     }
+    case CARBON_KIND(RequireImplsDecl inst): {
+      AddEntityNameAndMaybePush(inst.require_impls_id, ".decl");
+      auto require_scope_id = inst_namer_->GetScopeFor(inst.require_impls_id);
+      PushBlockId(require_scope_id, inst.decl_block_id);
+      return;
+    }
     case ReturnSlotPattern::Kind: {
       AddInstNameId(NameId::ReturnSlot, ".patt");
       return;

+ 8 - 4
toolchain/sem_ir/inst_namer.h

@@ -39,15 +39,15 @@ class InstNamer {
   // Entities whose scopes get entries from `ScopeId`.
   using ScopeIdTypeEnum =
       TypeEnum<AssociatedConstantId, ClassId, CppOverloadSetId, FunctionId,
-               ImplId, InterfaceId, NamedConstraintId, SpecificInterfaceId,
-               VtableId>;
+               ImplId, InterfaceId, NamedConstraintId, RequireImplsId,
+               SpecificInterfaceId, VtableId>;
 
   // Construct the instruction namer, and assign names to all instructions in
   // the provided file.
   explicit InstNamer(const File* sem_ir, int total_ir_count);
 
-  // Returns the scope ID corresponding to an ID of a function, class, or
-  // interface.
+  // Returns the scope ID corresponding to an ID of a function, class,
+  // interface, or named constraint.
   template <typename IdT>
     requires ScopeIdTypeEnum::Contains<IdT>
   auto GetScopeFor(IdT id) const -> ScopeId {
@@ -66,6 +66,8 @@ class InstNamer {
       index = sem_ir_->interfaces().GetRawIndex(id);
     } else if constexpr (std::is_same_v<IdT, NamedConstraintId>) {
       index = sem_ir_->named_constraints().GetRawIndex(id);
+    } else if constexpr (std::is_same_v<IdT, RequireImplsId>) {
+      index = sem_ir_->require_impls().GetRawIndex(id);
     } else if constexpr (std::is_same_v<IdT, SpecificInterfaceId>) {
       index = sem_ir_->specific_interfaces().GetRawIndex(id);
     } else if constexpr (std::is_same_v<IdT, VtableId>) {
@@ -223,6 +225,8 @@ class InstNamer {
       -> void;
   auto PushEntity(NamedConstraintId named_constraint_id, ScopeId scope_id,
                   Scope& scope) -> void;
+  auto PushEntity(RequireImplsId require_impls_id, ScopeId scope_id,
+                  Scope& scope) -> void;
   auto PushEntity(VtableId vtable_id, ScopeId scope_id, Scope& scope) -> void;
 
   // Always returns the name of the entity. May push it if it has not yet been

+ 51 - 0
toolchain/sem_ir/require_impls.h

@@ -0,0 +1,51 @@
+// 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_SEM_IR_REQUIRE_IMPLS_H_
+#define CARBON_TOOLCHAIN_SEM_IR_REQUIRE_IMPLS_H_
+
+#include "toolchain/base/canonical_value_store.h"
+#include "toolchain/sem_ir/ids.h"
+
+namespace Carbon::SemIR {
+
+// An interface requirement from an interface or named constraint, written
+// `require T impls Z`.
+//
+// While this comes from a `require` declaration, it is not an Entity like most
+// other declarations, with a name and parameters, so it does not inherit
+// EntityWithParamsBase.
+struct RequireImpls : Printable<RequireImpls> {
+  // The self-type which must implement a given facet type.
+  TypeInstId self_id;
+  // Evaluates to the `FacetType` that the self-type must implement.
+  TypeInstId facet_type_inst_id;
+  // The `FacetTypeInfo` derived from the `facet_type_inst_id` instruction.
+  FacetTypeId facet_type_id;
+
+  // The location of the `require` declaration.
+  InstId decl_id;
+  // The interface or named constraint which contains the `require` declaration.
+  NameScopeId parent_scope_id;
+  // The instructions that make up the `require` declaration. It will contain
+  // instructions that provide the `self_id` and `facet_type_inst_id`.
+  InstBlockId body_block_id;
+  // A `require` declaration is always generic over `Self` since it's inside an
+  // interface or named constraint definition.
+  GenericId generic_id;
+
+  auto Print(llvm::raw_ostream& out) const -> void {
+    out << '{';
+    out << "self_id: " << self_id
+        << ", facet_type_inst_id: " << facet_type_inst_id
+        << ", parent_scope: " << parent_scope_id;
+    out << '}';
+  }
+};
+
+using RequireImplsStore = ValueStore<RequireImplsId, RequireImpls>;
+
+}  // namespace Carbon::SemIR
+
+#endif  // CARBON_TOOLCHAIN_SEM_IR_REQUIRE_IMPLS_H_

+ 12 - 0
toolchain/sem_ir/typed_insts.h

@@ -1341,6 +1341,18 @@ struct RequireCompleteType {
   TypeInstId complete_type_inst_id;
 };
 
+// A `require` declaration, such as `require Self impls Z`.
+struct RequireImplsDecl {
+  static constexpr auto Kind =
+      InstKind::RequireImplsDecl.Define<Parse::RequireDeclId>(
+          {.ir_name = "require_decl",
+           .constant_kind = InstConstantKind::AlwaysUnique,
+           .is_lowered = false});
+
+  RequireImplsId require_impls_id;
+  DeclInstBlockId decl_block_id;
+};
+
 // A requirement that `.Self` implements a facet type, specified as the first
 // operand of a `where` expression. This is always the first requirement in a
 // requirement block for a `where` expression.