Ver código fonte

Stop allowing `impl` redeclarations to differ syntactically in `where` clause (#4850)

Based on [the lastest thinking on
#4672](https://github.com/carbon-language/carbon-lang/issues/4672#issuecomment-2606209281)
, require a full syntactic match for impl redeclaration, instead of
excluding the `where` restriction. This means no updates to the impl
witness on redeclaration, and no diagnostics that those updates are
consistent.

Not included in this PR, but will need to be done in the future:
* Support for assigning values to associated constants in the body of
the impl definition. This will require moving the checking that
non-function associated constants are set from the definition start to
definition end.
* Identify semantic redeclarations that are not syntactic matches to
give a failed redeclaration diagnostic. This should be done once we are
already identifying impl declarations with the same type structure in
order to require they be identified in an impl_priority/match_first
block.
* Merging of the functions in `check/impl.cpp` that are now always
called together.

Also add some test coverage of `where` parsing I developed in PR I've
now abandoned because of this new simplification of the impl
redeclaration semantics.

---------

Co-authored-by: Josh L <josh11b@users.noreply.github.com>
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
josh11b 1 ano atrás
pai
commit
5abe5a3c21

+ 4 - 36
toolchain/check/handle_impl.cpp

@@ -214,40 +214,11 @@ static auto PopImplIntroducerAndParamsAsNameComponent(
 
   Parse::NodeId first_param_node_id =
       context.node_stack().PopForSoloNodeId<Parse::NodeKind::ImplIntroducer>();
-
   // Subtracting 1 since we don't want to include the final `{` or `;` of the
   // declaration when performing syntactic match.
-  auto end_node_kind = context.parse_tree().node_kind(end_of_decl_node_id);
-  CARBON_CHECK(end_node_kind == Parse::NodeKind::ImplDefinitionStart ||
-               end_node_kind == Parse::NodeKind::ImplDecl);
   Parse::Tree::PostorderIterator last_param_iter(end_of_decl_node_id);
   --last_param_iter;
 
-  // Following proposal #3763, exclude a final `where` clause, if present. See:
-  // https://github.com/carbon-language/carbon-lang/blob/trunk/proposals/p3763.md#redeclarations
-
-  // Caches the NodeKind for the current value of *last_param_iter so
-  if (context.parse_tree().node_kind(*last_param_iter) ==
-      Parse::NodeKind::WhereExpr) {
-    int where_operands_to_skip = 1;
-    --last_param_iter;
-    CARBON_CHECK(Parse::Tree::PostorderIterator(first_param_node_id) <
-                 last_param_iter);
-    do {
-      auto node_kind = context.parse_tree().node_kind(*last_param_iter);
-      if (node_kind == Parse::NodeKind::WhereExpr) {
-        // If we have a nested `where`, we need to see another `WhereOperand`
-        // before we find the one that matches our original `WhereExpr` node.
-        ++where_operands_to_skip;
-      } else if (node_kind == Parse::NodeKind::WhereOperand) {
-        --where_operands_to_skip;
-      }
-      --last_param_iter;
-      CARBON_CHECK(Parse::Tree::PostorderIterator(first_param_node_id) <
-                   last_param_iter);
-    } while (where_operands_to_skip > 0);
-  }
-
   return {
       .name_loc_id = Parse::NodeId::None,
       .name_id = SemIR::NameId::None,
@@ -315,9 +286,6 @@ static auto IsValidImplRedecl(Context& context, SemIR::Impl& new_impl,
 
   // TODO: Only allow redeclaration in a match_first/impl_priority block.
 
-  // TODO: Merge information from the new declaration into the old one as
-  // needed.
-
   return true;
 }
 
@@ -375,6 +343,8 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId node_id,
   // Add the impl declaration.
   bool invalid_redeclaration = false;
   auto lookup_bucket_ref = context.impls().GetOrAddLookupBucket(impl_info);
+  // TODO: Detect two impl declarations with the same self type and interface,
+  // and issue an error if they don't match.
   for (auto prev_impl_id : lookup_bucket_ref) {
     if (MergeImplRedecl(context, impl_info, prev_impl_id)) {
       if (IsValidImplRedecl(context, impl_info, prev_impl_id)) {
@@ -392,15 +362,13 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId node_id,
   if (!impl_decl.impl_id.has_value()) {
     impl_info.generic_id = BuildGeneric(context, impl_decl_id);
     impl_info.witness_id = ImplWitnessForDeclaration(context, impl_info);
-    AddConstantsToImplWitnessFromConstraint(
-        context, impl_info, impl_info.witness_id, impl_decl.impl_id);
+    AddConstantsToImplWitnessFromConstraint(context, impl_info,
+                                            impl_info.witness_id);
     FinishGenericDecl(context, impl_decl_id, impl_info.generic_id);
     impl_decl.impl_id = context.impls().Add(impl_info);
     lookup_bucket_ref.push_back(impl_decl.impl_id);
   } else {
     const auto& first_impl = context.impls().Get(impl_decl.impl_id);
-    AddConstantsToImplWitnessFromConstraint(
-        context, impl_info, first_impl.witness_id, impl_decl.impl_id);
     FinishGenericRedecl(context, impl_decl_id, first_impl.generic_id);
   }
 

+ 9 - 50
toolchain/check/impl.cpp

@@ -32,16 +32,6 @@ static auto NoteAssociatedFunction(Context& context,
                function.name_id);
 }
 
-// Adds the location of the previous declaration to a diagnostic.
-static auto NotePreviousDecl(Context& context,
-                             Context::DiagnosticBuilder& builder,
-                             SemIR::ImplId impl_id) -> void {
-  CARBON_DIAGNOSTIC(ImplPreviousDeclHere, Note,
-                    "impl previously declared here");
-  const auto& impl = context.impls().Get(impl_id);
-  builder.Note(impl.latest_decl_id(), ImplPreviousDeclHere);
-}
-
 // Checks that `impl_function_id` is a valid implementation of the function
 // described in the interface as `interface_function_id`. Returns the value to
 // put into the corresponding slot in the witness table, which can be
@@ -88,6 +78,7 @@ static auto CheckAssociatedFunctionImplementation(
 }
 
 // Builds an initial empty witness.
+// TODO: Fill the witness with the rewrites from the declaration.
 auto ImplWitnessForDeclaration(Context& context, const SemIR::Impl& impl)
     -> SemIR::InstId {
   CARBON_CHECK(!impl.has_definition_started());
@@ -159,11 +150,10 @@ static auto WitnessAccessMatchesInterface(
   return false;
 }
 
+// TODO: Merge this function into `ImplWitnessForDeclaration`.
 auto AddConstantsToImplWitnessFromConstraint(Context& context,
                                              const SemIR::Impl& impl,
-                                             SemIR::InstId witness_id,
-                                             SemIR::ImplId prev_decl_id)
-    -> void {
+                                             SemIR::InstId witness_id) -> void {
   CARBON_CHECK(!impl.has_definition_started());
   CARBON_CHECK(witness_id.has_value());
   if (witness_id == SemIR::ErrorInst::SingletonInstId) {
@@ -229,16 +219,13 @@ auto AddConstantsToImplWitnessFromConstraint(Context& context,
     }
   }
 
-  // For each non-function associated constant, update witness entry.
+  // For each non-function associated constant, set the witness entry.
   for (auto index : llvm::seq(assoc_entities.size())) {
     auto decl_id =
         context.constant_values().GetConstantInstId(assoc_entities[index]);
     CARBON_CHECK(decl_id.has_value(), "Non-constant associated entity");
     if (auto decl =
             context.insts().TryGetAs<SemIR::AssociatedConstantDecl>(decl_id)) {
-      const auto& assoc_const =
-          context.associated_constants().Get(decl->assoc_const_id);
-      auto& witness_value = witness_block[index];
       auto rewrite_value = rewrite_values[index];
 
       // If the associated constant has a symbolic type, convert the rewrite
@@ -264,6 +251,8 @@ auto AddConstantsToImplWitnessFromConstraint(Context& context,
         // value was constant.
         if (!rewrite_value.is_constant() &&
             rewrite_value != SemIR::ErrorInst::SingletonConstantId) {
+          const auto& assoc_const =
+              context.associated_constants().Get(decl->assoc_const_id);
           CARBON_DIAGNOSTIC(
               AssociatedConstantNotConstantAfterConversion, Error,
               "associated constant {0} given value that is not constant "
@@ -276,39 +265,9 @@ auto AddConstantsToImplWitnessFromConstraint(Context& context,
         }
       }
 
-      if (witness_value.has_value() &&
-          witness_value != SemIR::ErrorInst::SingletonInstId) {
-        // TODO: Support just using the witness values if the redeclaration uses
-        // `where _`, per proposal #1084.
-        if (!rewrite_value.has_value()) {
-          CARBON_DIAGNOSTIC(AssociatedConstantMissingInRedecl, Error,
-                            "associated constant {0} given value in "
-                            "declaration but not redeclaration",
-                            SemIR::NameId);
-          auto builder = context.emitter().Build(
-              impl.latest_decl_id(), AssociatedConstantMissingInRedecl,
-              assoc_const.name_id);
-          NotePreviousDecl(context, builder, prev_decl_id);
-          builder.Emit();
-          continue;
-        }
-        auto witness_const_id = context.constant_values().Get(witness_value);
-        if (witness_const_id != rewrite_value &&
-            rewrite_value != SemIR::ErrorInst::SingletonConstantId) {
-          // TODO: Figure out how to print the two different values
-          CARBON_DIAGNOSTIC(
-              AssociatedConstantDifferentInRedecl, Error,
-              "redeclaration with different value for associated constant {0}",
-              SemIR::NameId);
-          auto builder = context.emitter().Build(
-              impl.latest_decl_id(), AssociatedConstantDifferentInRedecl,
-              assoc_const.name_id);
-          NotePreviousDecl(context, builder, prev_decl_id);
-          builder.Emit();
-          continue;
-        }
-      } else if (rewrite_value.has_value()) {
-        witness_value = context.constant_values().GetInstId(rewrite_value);
+      if (rewrite_value.has_value()) {
+        witness_block[index] =
+            context.constant_values().GetInstId(rewrite_value);
       }
     }
   }

+ 1 - 3
toolchain/check/impl.h

@@ -16,9 +16,7 @@ auto ImplWitnessForDeclaration(Context& context, const SemIR::Impl& impl)
 
 auto AddConstantsToImplWitnessFromConstraint(Context& context,
                                              const SemIR::Impl& impl,
-                                             SemIR::InstId witness_id,
-                                             SemIR::ImplId prev_decl_id)
-    -> void;
+                                             SemIR::InstId witness_id) -> void;
 
 // Update `impl`'s witness at the start of a definition.
 auto ImplWitnessStartDefinition(Context& context, SemIR::Impl& impl) -> void;

+ 142 - 123
toolchain/check/testdata/impl/no_prelude/impl_assoc_const.carbon

@@ -23,11 +23,15 @@ interface I2 { let T2:! type; }
 impl () as I2 where .T2 = {};
 impl () as I2 where .T2 = {} {}
 
-// --- redecl_adds_rewrites.carbon
+// --- fail_redecl_adds_rewrites.carbon
 library "[[@TEST_NAME]]";
 
 interface I3 { let T3:! type; }
 
+// CHECK:STDERR: fail_redecl_adds_rewrites.carbon:[[@LINE+4]]:1: error: impl declared but not defined [ImplMissingDefinition]
+// CHECK:STDERR: impl () as I3;
+// CHECK:STDERR: ^~~~~~~~~~~~~~
+// CHECK:STDERR:
 impl () as I3;
 impl () as I3 where .T3 = {} {}
 
@@ -36,14 +40,11 @@ library "[[@TEST_NAME]]";
 
 interface J { let U:! type; }
 
-impl () as J where .U = {};
-// CHECK:STDERR: fail_mismatch.carbon:[[@LINE+7]]:1: error: redeclaration with different value for associated constant U [AssociatedConstantDifferentInRedecl]
-// CHECK:STDERR: impl () as J where .U = () {}
-// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// CHECK:STDERR: fail_mismatch.carbon:[[@LINE-4]]:1: note: impl previously declared here [ImplPreviousDeclHere]
+// CHECK:STDERR: fail_mismatch.carbon:[[@LINE+4]]:1: error: impl declared but not defined [ImplMissingDefinition]
 // CHECK:STDERR: impl () as J where .U = {};
 // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
 // CHECK:STDERR:
+impl () as J where .U = {};
 impl () as J where .U = () {}
 
 // --- fail_mismatch_bad_value.carbon
@@ -55,10 +56,6 @@ interface I4 {
   let T6:! type;
 }
 
-// This is testing that it won't complain about mismatching values if one of
-// them is an error. Note that both impl declarations must have facet types
-// with errors in them or they won't match each other.
-
 // CHECK:STDERR: fail_mismatch_bad_value.carbon:[[@LINE+8]]:27: error: name `BAD1` not found [NameNotFound]
 // CHECK:STDERR: impl () as I4 where .T4 = BAD1 and .T5 = {.a: {}} and .T6 = BAD2;
 // CHECK:STDERR:                           ^~~~
@@ -69,14 +66,18 @@ interface I4 {
 // CHECK:STDERR:
 impl () as I4 where .T4 = BAD1 and .T5 = {.a: {}} and .T6 = BAD2;
 
-// CHECK:STDERR: fail_mismatch_bad_value.carbon:[[@LINE+8]]:46: error: name `BAD3` not found [NameNotFound]
+// CHECK:STDERR: fail_mismatch_bad_value.carbon:[[@LINE+12]]:46: error: name `BAD3` not found [NameNotFound]
 // CHECK:STDERR: impl () as I4 where .T4 = {.b: {}} and .T5 = BAD3 and .T6 = BAD4 {}
 // CHECK:STDERR:                                              ^~~~
 // CHECK:STDERR:
-// CHECK:STDERR: fail_mismatch_bad_value.carbon:[[@LINE+4]]:61: error: name `BAD4` not found [NameNotFound]
+// CHECK:STDERR: fail_mismatch_bad_value.carbon:[[@LINE+8]]:61: error: name `BAD4` not found [NameNotFound]
 // CHECK:STDERR: impl () as I4 where .T4 = {.b: {}} and .T5 = BAD3 and .T6 = BAD4 {}
 // CHECK:STDERR:                                                             ^~~~
 // CHECK:STDERR:
+// CHECK:STDERR: fail_mismatch_bad_value.carbon:[[@LINE-10]]:1: error: impl declared but not defined [ImplMissingDefinition]
+// CHECK:STDERR: impl () as I4 where .T4 = BAD1 and .T5 = {.a: {}} and .T6 = BAD2;
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR:
 impl () as I4 where .T4 = {.b: {}} and .T5 = BAD3 and .T6 = BAD4 {}
 
 // --- fail_missing_on_definition.carbon
@@ -85,10 +86,14 @@ library "[[@TEST_NAME]]";
 interface K { let V:! type; }
 
 impl () as K where .V = {};
-// CHECK:STDERR: fail_missing_on_definition.carbon:[[@LINE+7]]:1: error: associated constant V given value in declaration but not redeclaration [AssociatedConstantMissingInRedecl]
+// CHECK:STDERR: fail_missing_on_definition.carbon:[[@LINE+11]]:12: error: associated constant V not given a value in impl of interface K [ImplAssociatedConstantNeedsValue]
 // CHECK:STDERR: impl () as K {}
-// CHECK:STDERR: ^~~~~~~~~~~~~~
-// CHECK:STDERR: fail_missing_on_definition.carbon:[[@LINE-4]]:1: note: impl previously declared here [ImplPreviousDeclHere]
+// CHECK:STDERR:            ^
+// CHECK:STDERR: fail_missing_on_definition.carbon:[[@LINE-6]]:19: note: associated constant declared here [AssociatedConstantHere]
+// CHECK:STDERR: interface K { let V:! type; }
+// CHECK:STDERR:                   ^~~~~~~~
+// CHECK:STDERR:
+// CHECK:STDERR: fail_missing_on_definition.carbon:[[@LINE-8]]:1: error: impl declared but not defined [ImplMissingDefinition]
 // CHECK:STDERR: impl () as K where .V = {};
 // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
 // CHECK:STDERR:
@@ -311,7 +316,7 @@ impl () as N where .Y = {.a = {}} { }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @T2(constants.%I2.facet) {}
 // CHECK:STDOUT:
-// CHECK:STDOUT: --- redecl_adds_rewrites.carbon
+// CHECK:STDOUT: --- fail_redecl_adds_rewrites.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT:   %I3.type: type = facet_type <@I3> [template]
@@ -319,7 +324,7 @@ impl () as N where .Y = {.a = {}} { }
 // CHECK:STDOUT:   %I3.assoc_type: type = assoc_entity_type %I3.type [template]
 // CHECK:STDOUT:   %assoc0: %I3.assoc_type = assoc_entity element0, @I3.%T3 [template]
 // CHECK:STDOUT:   %empty_tuple.type: type = tuple_type () [template]
-// CHECK:STDOUT:   %impl_witness: <witness> = impl_witness (%empty_struct_type) [template]
+// CHECK:STDOUT:   %impl_witness.85b: <witness> = impl_witness (<error>) [template]
 // CHECK:STDOUT:   %.Self: %I3.type = bind_symbolic_name .Self [symbolic]
 // CHECK:STDOUT:   %.Self.as_type: type = facet_access_type %.Self [symbolic]
 // CHECK:STDOUT:   %.Self.as_wit: <witness> = facet_access_witness %.Self [symbolic]
@@ -327,6 +332,7 @@ impl () as N where .Y = {.a = {}} { }
 // CHECK:STDOUT:   %impl.elem0: type = impl_witness_access %.Self.as_wit, element0 [symbolic]
 // CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [template]
 // CHECK:STDOUT:   %I3_where.type: type = facet_type <@I3 where %impl.elem0 = %empty_struct_type> [template]
+// CHECK:STDOUT:   %impl_witness.6de: <witness> = impl_witness (%empty_struct_type) [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -334,29 +340,30 @@ impl () as N where .Y = {.a = {}} { }
 // CHECK:STDOUT:     .I3 = %I3.decl
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %I3.decl: type = interface_decl @I3 [template = constants.%I3.type] {} {}
-// CHECK:STDOUT:   impl_decl @impl [template] {} {
-// CHECK:STDOUT:     %.loc5_7.1: %empty_tuple.type = tuple_literal ()
-// CHECK:STDOUT:     %.loc5_7.2: type = converted %.loc5_7.1, constants.%empty_tuple.type [template = constants.%empty_tuple.type]
-// CHECK:STDOUT:     %I3.ref.loc5: type = name_ref I3, file.%I3.decl [template = constants.%I3.type]
+// CHECK:STDOUT:   impl_decl @impl.1 [template] {} {
+// CHECK:STDOUT:     %.loc9_7.1: %empty_tuple.type = tuple_literal ()
+// CHECK:STDOUT:     %.loc9_7.2: type = converted %.loc9_7.1, constants.%empty_tuple.type [template = constants.%empty_tuple.type]
+// CHECK:STDOUT:     %I3.ref: type = name_ref I3, file.%I3.decl [template = constants.%I3.type]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %impl_witness: <witness> = impl_witness (constants.%empty_struct_type) [template = constants.%impl_witness]
-// CHECK:STDOUT:   impl_decl @impl [template] {} {
-// CHECK:STDOUT:     %.loc6_7.1: %empty_tuple.type = tuple_literal ()
-// CHECK:STDOUT:     %.loc6_7.2: type = converted %.loc6_7.1, constants.%empty_tuple.type [template = constants.%empty_tuple.type]
-// CHECK:STDOUT:     %I3.ref.loc6: type = name_ref I3, file.%I3.decl [template = constants.%I3.type]
+// CHECK:STDOUT:   %impl_witness.loc9: <witness> = impl_witness (<error>) [template = constants.%impl_witness.85b]
+// CHECK:STDOUT:   impl_decl @impl.2 [template] {} {
+// CHECK:STDOUT:     %.loc10_7.1: %empty_tuple.type = tuple_literal ()
+// CHECK:STDOUT:     %.loc10_7.2: type = converted %.loc10_7.1, constants.%empty_tuple.type [template = constants.%empty_tuple.type]
+// CHECK:STDOUT:     %I3.ref: type = name_ref I3, file.%I3.decl [template = constants.%I3.type]
 // CHECK:STDOUT:     %.Self: %I3.type = bind_symbolic_name .Self [symbolic = constants.%.Self]
 // CHECK:STDOUT:     %.Self.ref: %I3.type = name_ref .Self, %.Self [symbolic = constants.%.Self]
 // CHECK:STDOUT:     %T3.ref: %I3.assoc_type = name_ref T3, @T3.%assoc0 [template = constants.%assoc0]
 // CHECK:STDOUT:     %.Self.as_type: type = facet_access_type %.Self.ref [symbolic = constants.%.Self.as_type]
-// CHECK:STDOUT:     %.loc6_21: type = converted %.Self.ref, %.Self.as_type [symbolic = constants.%.Self.as_type]
+// CHECK:STDOUT:     %.loc10_21: type = converted %.Self.ref, %.Self.as_type [symbolic = constants.%.Self.as_type]
 // CHECK:STDOUT:     %.Self.as_wit: <witness> = facet_access_witness %.Self.ref [symbolic = constants.%.Self.as_wit]
 // CHECK:STDOUT:     %impl.elem0: type = impl_witness_access %.Self.as_wit, element0 [symbolic = constants.%impl.elem0]
-// CHECK:STDOUT:     %.loc6_28.1: %empty_struct_type = struct_literal ()
-// CHECK:STDOUT:     %.loc6_28.2: type = converted %.loc6_28.1, constants.%empty_struct_type [template = constants.%empty_struct_type]
-// CHECK:STDOUT:     %.loc6_15: type = where_expr %.Self [template = constants.%I3_where.type] {
-// CHECK:STDOUT:       requirement_rewrite %impl.elem0, %.loc6_28.2
+// CHECK:STDOUT:     %.loc10_28.1: %empty_struct_type = struct_literal ()
+// CHECK:STDOUT:     %.loc10_28.2: type = converted %.loc10_28.1, constants.%empty_struct_type [template = constants.%empty_struct_type]
+// CHECK:STDOUT:     %.loc10_15: type = where_expr %.Self [template = constants.%I3_where.type] {
+// CHECK:STDOUT:       requirement_rewrite %impl.elem0, %.loc10_28.2
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:   }
+// CHECK:STDOUT:   %impl_witness.loc10: <witness> = impl_witness (constants.%empty_struct_type) [template = constants.%impl_witness.6de]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @I3 {
@@ -375,9 +382,11 @@ impl () as N where .Y = {.a = {}} { }
 // CHECK:STDOUT:   assoc_const T3:! type;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %.loc5_7.2 as %I3.ref.loc5 {
+// CHECK:STDOUT: impl @impl.1: %.loc9_7.2 as %I3.ref;
+// CHECK:STDOUT:
+// CHECK:STDOUT: impl @impl.2: %.loc10_7.2 as %.loc10_15 {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   witness = file.%impl_witness
+// CHECK:STDOUT:   witness = file.%impl_witness.loc10
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @T3(constants.%Self) {}
@@ -399,8 +408,9 @@ impl () as N where .Y = {.a = {}} { }
 // CHECK:STDOUT:   %impl.elem0: type = impl_witness_access %.Self.as_wit, element0 [symbolic]
 // CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [template]
 // CHECK:STDOUT:   %J_where.type.800: type = facet_type <@J where %impl.elem0 = %empty_struct_type> [template]
-// CHECK:STDOUT:   %impl_witness: <witness> = impl_witness (%empty_struct_type) [template]
+// CHECK:STDOUT:   %impl_witness.6de: <witness> = impl_witness (%empty_struct_type) [template]
 // CHECK:STDOUT:   %J_where.type.25a: type = facet_type <@J where %impl.elem0 = %empty_tuple.type> [template]
+// CHECK:STDOUT:   %impl_witness.2a6: <witness> = impl_witness (%empty_tuple.type) [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -408,41 +418,42 @@ impl () as N where .Y = {.a = {}} { }
 // CHECK:STDOUT:     .J = %J.decl
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %J.decl: type = interface_decl @J [template = constants.%J.type] {} {}
-// CHECK:STDOUT:   impl_decl @impl [template] {} {
-// CHECK:STDOUT:     %.loc5_7.1: %empty_tuple.type = tuple_literal ()
-// CHECK:STDOUT:     %.loc5_7.2: type = converted %.loc5_7.1, constants.%empty_tuple.type [template = constants.%empty_tuple.type]
-// CHECK:STDOUT:     %J.ref.loc5: type = name_ref J, file.%J.decl [template = constants.%J.type]
-// CHECK:STDOUT:     %.Self.1: %J.type = bind_symbolic_name .Self [symbolic = constants.%.Self]
-// CHECK:STDOUT:     %.Self.ref.loc5: %J.type = name_ref .Self, %.Self.1 [symbolic = constants.%.Self]
-// CHECK:STDOUT:     %U.ref.loc5: %J.assoc_type = name_ref U, @U.%assoc0 [template = constants.%assoc0]
-// CHECK:STDOUT:     %.Self.as_type.loc5: type = facet_access_type %.Self.ref.loc5 [symbolic = constants.%.Self.as_type]
-// CHECK:STDOUT:     %.loc5_20: type = converted %.Self.ref.loc5, %.Self.as_type.loc5 [symbolic = constants.%.Self.as_type]
-// CHECK:STDOUT:     %.Self.as_wit.loc5: <witness> = facet_access_witness %.Self.ref.loc5 [symbolic = constants.%.Self.as_wit]
-// CHECK:STDOUT:     %impl.elem0.loc5: type = impl_witness_access %.Self.as_wit.loc5, element0 [symbolic = constants.%impl.elem0]
-// CHECK:STDOUT:     %.loc5_26.1: %empty_struct_type = struct_literal ()
-// CHECK:STDOUT:     %.loc5_26.2: type = converted %.loc5_26.1, constants.%empty_struct_type [template = constants.%empty_struct_type]
-// CHECK:STDOUT:     %.loc5_14: type = where_expr %.Self.1 [template = constants.%J_where.type.800] {
-// CHECK:STDOUT:       requirement_rewrite %impl.elem0.loc5, %.loc5_26.2
+// CHECK:STDOUT:   impl_decl @impl.1 [template] {} {
+// CHECK:STDOUT:     %.loc9_7.1: %empty_tuple.type = tuple_literal ()
+// CHECK:STDOUT:     %.loc9_7.2: type = converted %.loc9_7.1, constants.%empty_tuple.type [template = constants.%empty_tuple.type]
+// CHECK:STDOUT:     %J.ref: type = name_ref J, file.%J.decl [template = constants.%J.type]
+// CHECK:STDOUT:     %.Self: %J.type = bind_symbolic_name .Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:     %.Self.ref: %J.type = name_ref .Self, %.Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:     %U.ref: %J.assoc_type = name_ref U, @U.%assoc0 [template = constants.%assoc0]
+// CHECK:STDOUT:     %.Self.as_type: type = facet_access_type %.Self.ref [symbolic = constants.%.Self.as_type]
+// CHECK:STDOUT:     %.loc9_20: type = converted %.Self.ref, %.Self.as_type [symbolic = constants.%.Self.as_type]
+// CHECK:STDOUT:     %.Self.as_wit: <witness> = facet_access_witness %.Self.ref [symbolic = constants.%.Self.as_wit]
+// CHECK:STDOUT:     %impl.elem0: type = impl_witness_access %.Self.as_wit, element0 [symbolic = constants.%impl.elem0]
+// CHECK:STDOUT:     %.loc9_26.1: %empty_struct_type = struct_literal ()
+// CHECK:STDOUT:     %.loc9_26.2: type = converted %.loc9_26.1, constants.%empty_struct_type [template = constants.%empty_struct_type]
+// CHECK:STDOUT:     %.loc9_14: type = where_expr %.Self [template = constants.%J_where.type.800] {
+// CHECK:STDOUT:       requirement_rewrite %impl.elem0, %.loc9_26.2
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %impl_witness: <witness> = impl_witness (constants.%empty_struct_type) [template = constants.%impl_witness]
-// CHECK:STDOUT:   impl_decl @impl [template] {} {
-// CHECK:STDOUT:     %.loc13_7.1: %empty_tuple.type = tuple_literal ()
-// CHECK:STDOUT:     %.loc13_7.2: type = converted %.loc13_7.1, constants.%empty_tuple.type [template = constants.%empty_tuple.type]
-// CHECK:STDOUT:     %J.ref.loc13: type = name_ref J, file.%J.decl [template = constants.%J.type]
-// CHECK:STDOUT:     %.Self.2: %J.type = bind_symbolic_name .Self [symbolic = constants.%.Self]
-// CHECK:STDOUT:     %.Self.ref.loc13: %J.type = name_ref .Self, %.Self.2 [symbolic = constants.%.Self]
-// CHECK:STDOUT:     %U.ref.loc13: %J.assoc_type = name_ref U, @U.%assoc0 [template = constants.%assoc0]
-// CHECK:STDOUT:     %.Self.as_type.loc13: type = facet_access_type %.Self.ref.loc13 [symbolic = constants.%.Self.as_type]
-// CHECK:STDOUT:     %.loc13_20: type = converted %.Self.ref.loc13, %.Self.as_type.loc13 [symbolic = constants.%.Self.as_type]
-// CHECK:STDOUT:     %.Self.as_wit.loc13: <witness> = facet_access_witness %.Self.ref.loc13 [symbolic = constants.%.Self.as_wit]
-// CHECK:STDOUT:     %impl.elem0.loc13: type = impl_witness_access %.Self.as_wit.loc13, element0 [symbolic = constants.%impl.elem0]
-// CHECK:STDOUT:     %.loc13_26.1: %empty_tuple.type = tuple_literal ()
-// CHECK:STDOUT:     %.loc13_26.2: type = converted %.loc13_26.1, constants.%empty_tuple.type [template = constants.%empty_tuple.type]
-// CHECK:STDOUT:     %.loc13_14: type = where_expr %.Self.2 [template = constants.%J_where.type.25a] {
-// CHECK:STDOUT:       requirement_rewrite %impl.elem0.loc13, %.loc13_26.2
+// CHECK:STDOUT:   %impl_witness.loc9: <witness> = impl_witness (constants.%empty_struct_type) [template = constants.%impl_witness.6de]
+// CHECK:STDOUT:   impl_decl @impl.2 [template] {} {
+// CHECK:STDOUT:     %.loc10_7.1: %empty_tuple.type = tuple_literal ()
+// CHECK:STDOUT:     %.loc10_7.2: type = converted %.loc10_7.1, constants.%empty_tuple.type [template = constants.%empty_tuple.type]
+// CHECK:STDOUT:     %J.ref: type = name_ref J, file.%J.decl [template = constants.%J.type]
+// CHECK:STDOUT:     %.Self: %J.type = bind_symbolic_name .Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:     %.Self.ref: %J.type = name_ref .Self, %.Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:     %U.ref: %J.assoc_type = name_ref U, @U.%assoc0 [template = constants.%assoc0]
+// CHECK:STDOUT:     %.Self.as_type: type = facet_access_type %.Self.ref [symbolic = constants.%.Self.as_type]
+// CHECK:STDOUT:     %.loc10_20: type = converted %.Self.ref, %.Self.as_type [symbolic = constants.%.Self.as_type]
+// CHECK:STDOUT:     %.Self.as_wit: <witness> = facet_access_witness %.Self.ref [symbolic = constants.%.Self.as_wit]
+// CHECK:STDOUT:     %impl.elem0: type = impl_witness_access %.Self.as_wit, element0 [symbolic = constants.%impl.elem0]
+// CHECK:STDOUT:     %.loc10_26.1: %empty_tuple.type = tuple_literal ()
+// CHECK:STDOUT:     %.loc10_26.2: type = converted %.loc10_26.1, constants.%empty_tuple.type [template = constants.%empty_tuple.type]
+// CHECK:STDOUT:     %.loc10_14: type = where_expr %.Self [template = constants.%J_where.type.25a] {
+// CHECK:STDOUT:       requirement_rewrite %impl.elem0, %.loc10_26.2
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:   }
+// CHECK:STDOUT:   %impl_witness.loc10: <witness> = impl_witness (constants.%empty_tuple.type) [template = constants.%impl_witness.2a6]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @J {
@@ -461,9 +472,11 @@ impl () as N where .Y = {.a = {}} { }
 // CHECK:STDOUT:   assoc_const U:! type;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %.loc5_7.2 as %.loc5_14 {
+// CHECK:STDOUT: impl @impl.1: %.loc9_7.2 as %.loc9_14;
+// CHECK:STDOUT:
+// CHECK:STDOUT: impl @impl.2: %.loc10_7.2 as %.loc10_14 {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   witness = file.%impl_witness
+// CHECK:STDOUT:   witness = file.%impl_witness.loc10
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @U(constants.%Self) {}
@@ -497,72 +510,72 @@ impl () as N where .Y = {.a = {}} { }
 // CHECK:STDOUT:     .I4 = %I4.decl
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %I4.decl: type = interface_decl @I4 [template = constants.%I4.type] {} {}
-// CHECK:STDOUT:   impl_decl @impl [template] {} {
-// CHECK:STDOUT:     %.loc21_7.1: %empty_tuple.type = tuple_literal ()
-// CHECK:STDOUT:     %.loc21_7.2: type = converted %.loc21_7.1, constants.%empty_tuple.type [template = constants.%empty_tuple.type]
-// CHECK:STDOUT:     %I4.ref.loc21: type = name_ref I4, file.%I4.decl [template = constants.%I4.type]
-// CHECK:STDOUT:     %.Self.1: %I4.type = bind_symbolic_name .Self [symbolic = constants.%.Self]
-// CHECK:STDOUT:     %.Self.ref.loc21_21: %I4.type = name_ref .Self, %.Self.1 [symbolic = constants.%.Self]
-// CHECK:STDOUT:     %T4.ref.loc21: %I4.assoc_type = name_ref T4, @T4.%assoc0 [template = constants.%assoc0]
-// CHECK:STDOUT:     %.Self.as_type.loc21_21: type = facet_access_type %.Self.ref.loc21_21 [symbolic = constants.%.Self.as_type]
-// CHECK:STDOUT:     %.loc21_21: type = converted %.Self.ref.loc21_21, %.Self.as_type.loc21_21 [symbolic = constants.%.Self.as_type]
-// CHECK:STDOUT:     %.Self.as_wit.loc21_21: <witness> = facet_access_witness %.Self.ref.loc21_21 [symbolic = constants.%.Self.as_wit]
-// CHECK:STDOUT:     %impl.elem0.loc21: type = impl_witness_access %.Self.as_wit.loc21_21, element0 [symbolic = constants.%impl.elem0]
+// CHECK:STDOUT:   impl_decl @impl.1 [template] {} {
+// CHECK:STDOUT:     %.loc17_7.1: %empty_tuple.type = tuple_literal ()
+// CHECK:STDOUT:     %.loc17_7.2: type = converted %.loc17_7.1, constants.%empty_tuple.type [template = constants.%empty_tuple.type]
+// CHECK:STDOUT:     %I4.ref: type = name_ref I4, file.%I4.decl [template = constants.%I4.type]
+// CHECK:STDOUT:     %.Self: %I4.type = bind_symbolic_name .Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:     %.Self.ref.loc17_21: %I4.type = name_ref .Self, %.Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:     %T4.ref: %I4.assoc_type = name_ref T4, @T4.%assoc0 [template = constants.%assoc0]
+// CHECK:STDOUT:     %.Self.as_type.loc17_21: type = facet_access_type %.Self.ref.loc17_21 [symbolic = constants.%.Self.as_type]
+// CHECK:STDOUT:     %.loc17_21: type = converted %.Self.ref.loc17_21, %.Self.as_type.loc17_21 [symbolic = constants.%.Self.as_type]
+// CHECK:STDOUT:     %.Self.as_wit.loc17_21: <witness> = facet_access_witness %.Self.ref.loc17_21 [symbolic = constants.%.Self.as_wit]
+// CHECK:STDOUT:     %impl.elem0: type = impl_witness_access %.Self.as_wit.loc17_21, element0 [symbolic = constants.%impl.elem0]
 // CHECK:STDOUT:     %BAD1.ref: <error> = name_ref BAD1, <error> [template = <error>]
-// CHECK:STDOUT:     %.Self.ref.loc21_36: %I4.type = name_ref .Self, %.Self.1 [symbolic = constants.%.Self]
-// CHECK:STDOUT:     %T5.ref.loc21: %I4.assoc_type = name_ref T5, @T5.%assoc1 [template = constants.%assoc1]
-// CHECK:STDOUT:     %.Self.as_type.loc21_36: type = facet_access_type %.Self.ref.loc21_36 [symbolic = constants.%.Self.as_type]
-// CHECK:STDOUT:     %.loc21_36: type = converted %.Self.ref.loc21_36, %.Self.as_type.loc21_36 [symbolic = constants.%.Self.as_type]
-// CHECK:STDOUT:     %.Self.as_wit.loc21_36: <witness> = facet_access_witness %.Self.ref.loc21_36 [symbolic = constants.%.Self.as_wit]
-// CHECK:STDOUT:     %impl.elem1.loc21: type = impl_witness_access %.Self.as_wit.loc21_36, element1 [symbolic = constants.%impl.elem1]
-// CHECK:STDOUT:     %.loc21_48.1: %empty_struct_type = struct_literal ()
-// CHECK:STDOUT:     %.loc21_48.2: type = converted %.loc21_48.1, constants.%empty_struct_type [template = constants.%empty_struct_type]
+// CHECK:STDOUT:     %.Self.ref.loc17_36: %I4.type = name_ref .Self, %.Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:     %T5.ref: %I4.assoc_type = name_ref T5, @T5.%assoc1 [template = constants.%assoc1]
+// CHECK:STDOUT:     %.Self.as_type.loc17_36: type = facet_access_type %.Self.ref.loc17_36 [symbolic = constants.%.Self.as_type]
+// CHECK:STDOUT:     %.loc17_36: type = converted %.Self.ref.loc17_36, %.Self.as_type.loc17_36 [symbolic = constants.%.Self.as_type]
+// CHECK:STDOUT:     %.Self.as_wit.loc17_36: <witness> = facet_access_witness %.Self.ref.loc17_36 [symbolic = constants.%.Self.as_wit]
+// CHECK:STDOUT:     %impl.elem1: type = impl_witness_access %.Self.as_wit.loc17_36, element1 [symbolic = constants.%impl.elem1]
+// CHECK:STDOUT:     %.loc17_48.1: %empty_struct_type = struct_literal ()
+// CHECK:STDOUT:     %.loc17_48.2: type = converted %.loc17_48.1, constants.%empty_struct_type [template = constants.%empty_struct_type]
 // CHECK:STDOUT:     %struct_type.a: type = struct_type {.a: %empty_struct_type} [template = constants.%struct_type.a]
-// CHECK:STDOUT:     %.Self.ref.loc21_55: %I4.type = name_ref .Self, %.Self.1 [symbolic = constants.%.Self]
-// CHECK:STDOUT:     %T6.ref.loc21: %I4.assoc_type = name_ref T6, @T6.%assoc2 [template = constants.%assoc2]
-// CHECK:STDOUT:     %.Self.as_type.loc21_55: type = facet_access_type %.Self.ref.loc21_55 [symbolic = constants.%.Self.as_type]
-// CHECK:STDOUT:     %.loc21_55: type = converted %.Self.ref.loc21_55, %.Self.as_type.loc21_55 [symbolic = constants.%.Self.as_type]
-// CHECK:STDOUT:     %.Self.as_wit.loc21_55: <witness> = facet_access_witness %.Self.ref.loc21_55 [symbolic = constants.%.Self.as_wit]
-// CHECK:STDOUT:     %impl.elem2.loc21: type = impl_witness_access %.Self.as_wit.loc21_55, element2 [symbolic = constants.%impl.elem2]
+// CHECK:STDOUT:     %.Self.ref.loc17_55: %I4.type = name_ref .Self, %.Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:     %T6.ref: %I4.assoc_type = name_ref T6, @T6.%assoc2 [template = constants.%assoc2]
+// CHECK:STDOUT:     %.Self.as_type.loc17_55: type = facet_access_type %.Self.ref.loc17_55 [symbolic = constants.%.Self.as_type]
+// CHECK:STDOUT:     %.loc17_55: type = converted %.Self.ref.loc17_55, %.Self.as_type.loc17_55 [symbolic = constants.%.Self.as_type]
+// CHECK:STDOUT:     %.Self.as_wit.loc17_55: <witness> = facet_access_witness %.Self.ref.loc17_55 [symbolic = constants.%.Self.as_wit]
+// CHECK:STDOUT:     %impl.elem2: type = impl_witness_access %.Self.as_wit.loc17_55, element2 [symbolic = constants.%impl.elem2]
 // CHECK:STDOUT:     %BAD2.ref: <error> = name_ref BAD2, <error> [template = <error>]
-// CHECK:STDOUT:     %.loc21_15: type = where_expr %.Self.1 [template = <error>] {
-// CHECK:STDOUT:       requirement_rewrite %impl.elem0.loc21, <error>
-// CHECK:STDOUT:       requirement_rewrite %impl.elem1.loc21, %struct_type.a
-// CHECK:STDOUT:       requirement_rewrite %impl.elem2.loc21, <error>
+// CHECK:STDOUT:     %.loc17_15: type = where_expr %.Self [template = <error>] {
+// CHECK:STDOUT:       requirement_rewrite %impl.elem0, <error>
+// CHECK:STDOUT:       requirement_rewrite %impl.elem1, %struct_type.a
+// CHECK:STDOUT:       requirement_rewrite %impl.elem2, <error>
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   impl_decl @impl [template] {} {
+// CHECK:STDOUT:   impl_decl @impl.2 [template] {} {
 // CHECK:STDOUT:     %.loc31_7.1: %empty_tuple.type = tuple_literal ()
 // CHECK:STDOUT:     %.loc31_7.2: type = converted %.loc31_7.1, constants.%empty_tuple.type [template = constants.%empty_tuple.type]
-// CHECK:STDOUT:     %I4.ref.loc31: type = name_ref I4, file.%I4.decl [template = constants.%I4.type]
-// CHECK:STDOUT:     %.Self.2: %I4.type = bind_symbolic_name .Self [symbolic = constants.%.Self]
-// CHECK:STDOUT:     %.Self.ref.loc31_21: %I4.type = name_ref .Self, %.Self.2 [symbolic = constants.%.Self]
-// CHECK:STDOUT:     %T4.ref.loc31: %I4.assoc_type = name_ref T4, @T4.%assoc0 [template = constants.%assoc0]
+// CHECK:STDOUT:     %I4.ref: type = name_ref I4, file.%I4.decl [template = constants.%I4.type]
+// CHECK:STDOUT:     %.Self: %I4.type = bind_symbolic_name .Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:     %.Self.ref.loc31_21: %I4.type = name_ref .Self, %.Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:     %T4.ref: %I4.assoc_type = name_ref T4, @T4.%assoc0 [template = constants.%assoc0]
 // CHECK:STDOUT:     %.Self.as_type.loc31_21: type = facet_access_type %.Self.ref.loc31_21 [symbolic = constants.%.Self.as_type]
 // CHECK:STDOUT:     %.loc31_21: type = converted %.Self.ref.loc31_21, %.Self.as_type.loc31_21 [symbolic = constants.%.Self.as_type]
 // CHECK:STDOUT:     %.Self.as_wit.loc31_21: <witness> = facet_access_witness %.Self.ref.loc31_21 [symbolic = constants.%.Self.as_wit]
-// CHECK:STDOUT:     %impl.elem0.loc31: type = impl_witness_access %.Self.as_wit.loc31_21, element0 [symbolic = constants.%impl.elem0]
+// CHECK:STDOUT:     %impl.elem0: type = impl_witness_access %.Self.as_wit.loc31_21, element0 [symbolic = constants.%impl.elem0]
 // CHECK:STDOUT:     %.loc31_33.1: %empty_struct_type = struct_literal ()
 // CHECK:STDOUT:     %.loc31_33.2: type = converted %.loc31_33.1, constants.%empty_struct_type [template = constants.%empty_struct_type]
 // CHECK:STDOUT:     %struct_type.b: type = struct_type {.b: %empty_struct_type} [template = constants.%struct_type.b]
-// CHECK:STDOUT:     %.Self.ref.loc31_40: %I4.type = name_ref .Self, %.Self.2 [symbolic = constants.%.Self]
-// CHECK:STDOUT:     %T5.ref.loc31: %I4.assoc_type = name_ref T5, @T5.%assoc1 [template = constants.%assoc1]
+// CHECK:STDOUT:     %.Self.ref.loc31_40: %I4.type = name_ref .Self, %.Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:     %T5.ref: %I4.assoc_type = name_ref T5, @T5.%assoc1 [template = constants.%assoc1]
 // CHECK:STDOUT:     %.Self.as_type.loc31_40: type = facet_access_type %.Self.ref.loc31_40 [symbolic = constants.%.Self.as_type]
 // CHECK:STDOUT:     %.loc31_40: type = converted %.Self.ref.loc31_40, %.Self.as_type.loc31_40 [symbolic = constants.%.Self.as_type]
 // CHECK:STDOUT:     %.Self.as_wit.loc31_40: <witness> = facet_access_witness %.Self.ref.loc31_40 [symbolic = constants.%.Self.as_wit]
-// CHECK:STDOUT:     %impl.elem1.loc31: type = impl_witness_access %.Self.as_wit.loc31_40, element1 [symbolic = constants.%impl.elem1]
+// CHECK:STDOUT:     %impl.elem1: type = impl_witness_access %.Self.as_wit.loc31_40, element1 [symbolic = constants.%impl.elem1]
 // CHECK:STDOUT:     %BAD3.ref: <error> = name_ref BAD3, <error> [template = <error>]
-// CHECK:STDOUT:     %.Self.ref.loc31_55: %I4.type = name_ref .Self, %.Self.2 [symbolic = constants.%.Self]
-// CHECK:STDOUT:     %T6.ref.loc31: %I4.assoc_type = name_ref T6, @T6.%assoc2 [template = constants.%assoc2]
+// CHECK:STDOUT:     %.Self.ref.loc31_55: %I4.type = name_ref .Self, %.Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:     %T6.ref: %I4.assoc_type = name_ref T6, @T6.%assoc2 [template = constants.%assoc2]
 // CHECK:STDOUT:     %.Self.as_type.loc31_55: type = facet_access_type %.Self.ref.loc31_55 [symbolic = constants.%.Self.as_type]
 // CHECK:STDOUT:     %.loc31_55: type = converted %.Self.ref.loc31_55, %.Self.as_type.loc31_55 [symbolic = constants.%.Self.as_type]
 // CHECK:STDOUT:     %.Self.as_wit.loc31_55: <witness> = facet_access_witness %.Self.ref.loc31_55 [symbolic = constants.%.Self.as_wit]
-// CHECK:STDOUT:     %impl.elem2.loc31: type = impl_witness_access %.Self.as_wit.loc31_55, element2 [symbolic = constants.%impl.elem2]
+// CHECK:STDOUT:     %impl.elem2: type = impl_witness_access %.Self.as_wit.loc31_55, element2 [symbolic = constants.%impl.elem2]
 // CHECK:STDOUT:     %BAD4.ref: <error> = name_ref BAD4, <error> [template = <error>]
-// CHECK:STDOUT:     %.loc31_15: type = where_expr %.Self.2 [template = <error>] {
-// CHECK:STDOUT:       requirement_rewrite %impl.elem0.loc31, %struct_type.b
-// CHECK:STDOUT:       requirement_rewrite %impl.elem1.loc31, <error>
-// CHECK:STDOUT:       requirement_rewrite %impl.elem2.loc31, <error>
+// CHECK:STDOUT:     %.loc31_15: type = where_expr %.Self [template = <error>] {
+// CHECK:STDOUT:       requirement_rewrite %impl.elem0, %struct_type.b
+// CHECK:STDOUT:       requirement_rewrite %impl.elem1, <error>
+// CHECK:STDOUT:       requirement_rewrite %impl.elem2, <error>
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
@@ -599,7 +612,9 @@ impl () as N where .Y = {.a = {}} { }
 // CHECK:STDOUT:   assoc_const T6:! type;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %.loc21_7.2 as %.loc21_15 {
+// CHECK:STDOUT: impl @impl.1: %.loc17_7.2 as %.loc17_15;
+// CHECK:STDOUT:
+// CHECK:STDOUT: impl @impl.2: %.loc31_7.2 as %.loc31_15 {
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   witness = <error>
 // CHECK:STDOUT: }
@@ -631,7 +646,8 @@ impl () as N where .Y = {.a = {}} { }
 // CHECK:STDOUT:   %impl.elem0: type = impl_witness_access %.Self.as_wit, element0 [symbolic]
 // CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [template]
 // CHECK:STDOUT:   %K_where.type: type = facet_type <@K where %impl.elem0 = %empty_struct_type> [template]
-// CHECK:STDOUT:   %impl_witness: <witness> = impl_witness (%empty_struct_type) [template]
+// CHECK:STDOUT:   %impl_witness.6de: <witness> = impl_witness (%empty_struct_type) [template]
+// CHECK:STDOUT:   %impl_witness.85b: <witness> = impl_witness (<error>) [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -639,10 +655,10 @@ impl () as N where .Y = {.a = {}} { }
 // CHECK:STDOUT:     .K = %K.decl
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %K.decl: type = interface_decl @K [template = constants.%K.type] {} {}
-// CHECK:STDOUT:   impl_decl @impl [template] {} {
+// CHECK:STDOUT:   impl_decl @impl.1 [template] {} {
 // CHECK:STDOUT:     %.loc5_7.1: %empty_tuple.type = tuple_literal ()
 // CHECK:STDOUT:     %.loc5_7.2: type = converted %.loc5_7.1, constants.%empty_tuple.type [template = constants.%empty_tuple.type]
-// CHECK:STDOUT:     %K.ref.loc5: type = name_ref K, file.%K.decl [template = constants.%K.type]
+// CHECK:STDOUT:     %K.ref: type = name_ref K, file.%K.decl [template = constants.%K.type]
 // CHECK:STDOUT:     %.Self: %K.type = bind_symbolic_name .Self [symbolic = constants.%.Self]
 // CHECK:STDOUT:     %.Self.ref: %K.type = name_ref .Self, %.Self [symbolic = constants.%.Self]
 // CHECK:STDOUT:     %V.ref: %K.assoc_type = name_ref V, @V.%assoc0 [template = constants.%assoc0]
@@ -656,12 +672,13 @@ impl () as N where .Y = {.a = {}} { }
 // CHECK:STDOUT:       requirement_rewrite %impl.elem0, %.loc5_26.2
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %impl_witness: <witness> = impl_witness (constants.%empty_struct_type) [template = constants.%impl_witness]
-// CHECK:STDOUT:   impl_decl @impl [template] {} {
-// CHECK:STDOUT:     %.loc13_7.1: %empty_tuple.type = tuple_literal ()
-// CHECK:STDOUT:     %.loc13_7.2: type = converted %.loc13_7.1, constants.%empty_tuple.type [template = constants.%empty_tuple.type]
-// CHECK:STDOUT:     %K.ref.loc13: type = name_ref K, file.%K.decl [template = constants.%K.type]
+// CHECK:STDOUT:   %impl_witness.loc5: <witness> = impl_witness (constants.%empty_struct_type) [template = constants.%impl_witness.6de]
+// CHECK:STDOUT:   impl_decl @impl.2 [template] {} {
+// CHECK:STDOUT:     %.loc17_7.1: %empty_tuple.type = tuple_literal ()
+// CHECK:STDOUT:     %.loc17_7.2: type = converted %.loc17_7.1, constants.%empty_tuple.type [template = constants.%empty_tuple.type]
+// CHECK:STDOUT:     %K.ref: type = name_ref K, file.%K.decl [template = constants.%K.type]
 // CHECK:STDOUT:   }
+// CHECK:STDOUT:   %impl_witness.loc17: <witness> = impl_witness (<error>) [template = constants.%impl_witness.85b]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @K {
@@ -680,9 +697,11 @@ impl () as N where .Y = {.a = {}} { }
 // CHECK:STDOUT:   assoc_const V:! type;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %.loc5_7.2 as %.loc5_14 {
+// CHECK:STDOUT: impl @impl.1: %.loc5_7.2 as %.loc5_14;
+// CHECK:STDOUT:
+// CHECK:STDOUT: impl @impl.2: %.loc17_7.2 as %K.ref {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   witness = file.%impl_witness
+// CHECK:STDOUT:   witness = file.%impl_witness.loc17
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @V(constants.%Self) {}

+ 33 - 9
toolchain/check/testdata/impl/no_prelude/impl_where_redecl.carbon

@@ -10,38 +10,62 @@
 // TIP: To dump output, run:
 // TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/impl/no_prelude/impl_where_redecl.carbon
 
-// --- match.carbon
+// `impl` declarations only match when they are the same syntactically.
+
+// --- fail_match_with_associated_type.carbon
 library "[[@TEST_NAME]]";
 
 interface I { let T:! type; }
-interface J {}
-
-// `impl` matching ignores the `where` clause. It should not get confused by
-// nested `where`, so the following should not trigger impl declaration without
-// definition diagnostics.
 
+// CHECK:STDERR: fail_match_with_associated_type.carbon:[[@LINE+4]]:1: error: impl declared but not defined [ImplMissingDefinition]
+// CHECK:STDERR: impl () as I where .T = {};
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR:
 impl () as I where .T = {};
 impl () as I where .T = {} and .T impls (type where .Self impls type) {}
 
+// CHECK:STDERR: fail_match_with_associated_type.carbon:[[@LINE+4]]:1: error: impl declared but not defined [ImplMissingDefinition]
+// CHECK:STDERR: impl {} as I;
+// CHECK:STDERR: ^~~~~~~~~~~~~
+// CHECK:STDERR:
 impl {} as I;
 impl {} as I where .T = {} and .T impls (type where .Self impls type) {}
 
+// CHECK:STDERR: fail_match_with_associated_type.carbon:[[@LINE+4]]:1: error: impl declared but not defined [ImplMissingDefinition]
+// CHECK:STDERR: impl ({},) as I where .T = {} and .T impls (type where .Self impls type);
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR:
 impl ({},) as I where .T = {} and .T impls (type where .Self impls type);
 impl ({},) as I where .T = {} {}
 
+// --- fail_match_with_empty_interface.carbon
+library "[[@TEST_NAME]]";
+
+interface J {}
+
+// CHECK:STDERR: fail_match_with_empty_interface.carbon:[[@LINE+4]]:1: error: impl declared but not defined [ImplMissingDefinition]
+// CHECK:STDERR: impl () as J;
+// CHECK:STDERR: ^~~~~~~~~~~~~
+// CHECK:STDERR:
 impl () as J;
 impl () as J where .Self impls type and .Self impls (type where .Self impls type) {}
 
+// CHECK:STDERR: fail_match_with_empty_interface.carbon:[[@LINE+4]]:1: error: impl declared but not defined [ImplMissingDefinition]
+// CHECK:STDERR: impl {} as J where .Self impls type and .Self impls (type where .Self impls type);
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR:
 impl {} as J where .Self impls type and .Self impls (type where .Self impls type);
 impl {} as J {}
 
-// --- parens_other_nesting.carbon
+// --- fail_parens_other_nesting.carbon
 library "[[@TEST_NAME]]";
 
 interface K {}
 
-// `impl` matching only ignores a root-level `where` clause.
-
+// CHECK:STDERR: fail_parens_other_nesting.carbon:[[@LINE+4]]:1: error: impl declared but not defined [ImplMissingDefinition]
+// CHECK:STDERR: impl {} as (K where .Self impls type) where .Self impls type;
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR:
 impl {} as (K where .Self impls type) where .Self impls type;
 impl {} as (K where .Self impls type) {}
 

+ 139 - 115
toolchain/check/testdata/impl/no_prelude/import_interface_assoc_const.carbon

@@ -38,11 +38,15 @@ class C2 { }
 impl C2 as I where .T = {};
 impl C2 as I where .T = {} { }
 
-// --- redecl_adds_rewrites.carbon
+// --- fail_redecl_adds_rewrites.carbon
 library "[[@TEST_NAME]]";
 import library "interface";
 
 class C3 { }
+// CHECK:STDERR: fail_redecl_adds_rewrites.carbon:[[@LINE+4]]:1: error: impl declared but not defined [ImplMissingDefinition]
+// CHECK:STDERR: impl C3 as I;
+// CHECK:STDERR: ^~~~~~~~~~~~~
+// CHECK:STDERR:
 impl C3 as I;
 impl C3 as I where .T = {} { }
 
@@ -51,14 +55,11 @@ library "[[@TEST_NAME]]";
 import library "interface";
 
 class C4 { }
-impl C4 as I where .T = {};
-// CHECK:STDERR: fail_mismatch.carbon:[[@LINE+7]]:1: error: redeclaration with different value for associated constant T [AssociatedConstantDifferentInRedecl]
-// CHECK:STDERR: impl C4 as I where .T = () { }
-// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// CHECK:STDERR: fail_mismatch.carbon:[[@LINE-4]]:1: note: impl previously declared here [ImplPreviousDeclHere]
+// CHECK:STDERR: fail_mismatch.carbon:[[@LINE+4]]:1: error: impl declared but not defined [ImplMissingDefinition]
 // CHECK:STDERR: impl C4 as I where .T = {};
 // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
 // CHECK:STDERR:
+impl C4 as I where .T = {};
 impl C4 as I where .T = () { }
 
 // --- fail_mismatch_bad_value.carbon
@@ -81,14 +82,18 @@ class C5 { }
 // CHECK:STDERR:
 impl C5 as I3 where .T1 = BAD1 and .T2 = {.a: {}} and .T3 = BAD2;
 
-// CHECK:STDERR: fail_mismatch_bad_value.carbon:[[@LINE+8]]:46: error: name `BAD3` not found [NameNotFound]
+// CHECK:STDERR: fail_mismatch_bad_value.carbon:[[@LINE+12]]:46: error: name `BAD3` not found [NameNotFound]
 // CHECK:STDERR: impl C5 as I3 where .T1 = {.b: {}} and .T2 = BAD3 and .T3 = BAD4 { }
 // CHECK:STDERR:                                              ^~~~
 // CHECK:STDERR:
-// CHECK:STDERR: fail_mismatch_bad_value.carbon:[[@LINE+4]]:61: error: name `BAD4` not found [NameNotFound]
+// CHECK:STDERR: fail_mismatch_bad_value.carbon:[[@LINE+8]]:61: error: name `BAD4` not found [NameNotFound]
 // CHECK:STDERR: impl C5 as I3 where .T1 = {.b: {}} and .T2 = BAD3 and .T3 = BAD4 { }
 // CHECK:STDERR:                                                             ^~~~
 // CHECK:STDERR:
+// CHECK:STDERR: fail_mismatch_bad_value.carbon:[[@LINE-10]]:1: error: impl declared but not defined [ImplMissingDefinition]
+// CHECK:STDERR: impl C5 as I3 where .T1 = BAD1 and .T2 = {.a: {}} and .T3 = BAD2;
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR:
 impl C5 as I3 where .T1 = {.b: {}} and .T2 = BAD3 and .T3 = BAD4 { }
 
 // --- fail_missing_on_definition.carbon
@@ -97,10 +102,15 @@ import library "interface";
 
 class C6 { }
 impl C6 as I where .T = {};
-// CHECK:STDERR: fail_missing_on_definition.carbon:[[@LINE+7]]:1: error: associated constant T given value in declaration but not redeclaration [AssociatedConstantMissingInRedecl]
+// CHECK:STDERR: fail_missing_on_definition.carbon:[[@LINE+12]]:12: error: associated constant T not given a value in impl of interface I [ImplAssociatedConstantNeedsValue]
 // CHECK:STDERR: impl C6 as I { }
-// CHECK:STDERR: ^~~~~~~~~~~~~~
-// CHECK:STDERR: fail_missing_on_definition.carbon:[[@LINE-4]]:1: note: impl previously declared here [ImplPreviousDeclHere]
+// CHECK:STDERR:            ^
+// CHECK:STDERR: fail_missing_on_definition.carbon:[[@LINE-7]]:1: in import [InImport]
+// CHECK:STDERR: interface.carbon:3:19: note: associated constant declared here [AssociatedConstantHere]
+// CHECK:STDERR: interface I { let T:! type; }
+// CHECK:STDERR:                   ^~~~~~~~
+// CHECK:STDERR:
+// CHECK:STDERR: fail_missing_on_definition.carbon:[[@LINE-9]]:1: error: impl declared but not defined [ImplMissingDefinition]
 // CHECK:STDERR: impl C6 as I where .T = {};
 // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
 // CHECK:STDERR:
@@ -464,7 +474,7 @@ impl CC as NonType where .Y = {.a = {}} { }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @T(constants.%I.facet) {}
 // CHECK:STDOUT:
-// CHECK:STDOUT: --- redecl_adds_rewrites.carbon
+// CHECK:STDOUT: --- fail_redecl_adds_rewrites.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT:   %C3: type = class_type @C3 [template]
@@ -472,7 +482,7 @@ impl CC as NonType where .Y = {.a = {}} { }
 // CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %empty_struct_type [template]
 // CHECK:STDOUT:   %I.type: type = facet_type <@I> [template]
 // CHECK:STDOUT:   %Self: %I.type = bind_symbolic_name Self, 0 [symbolic]
-// CHECK:STDOUT:   %impl_witness: <witness> = impl_witness (%empty_struct_type) [template]
+// CHECK:STDOUT:   %impl_witness.85b: <witness> = impl_witness (<error>) [template]
 // CHECK:STDOUT:   %.Self: %I.type = bind_symbolic_name .Self [symbolic]
 // CHECK:STDOUT:   %I.assoc_type: type = assoc_entity_type %I.type [template]
 // CHECK:STDOUT:   %assoc0: %I.assoc_type = assoc_entity element0, imports.%Main.import_ref.652 [template]
@@ -481,6 +491,7 @@ impl CC as NonType where .Y = {.a = {}} { }
 // CHECK:STDOUT:   %I.facet: %I.type = facet_value %.Self.as_type, %.Self.as_wit [symbolic]
 // CHECK:STDOUT:   %impl.elem0: type = impl_witness_access %.Self.as_wit, element0 [symbolic]
 // CHECK:STDOUT:   %I_where.type: type = facet_type <@I where %impl.elem0 = %empty_struct_type> [template]
+// CHECK:STDOUT:   %impl_witness.6de: <witness> = impl_witness (%empty_struct_type) [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -501,27 +512,28 @@ impl CC as NonType where .Y = {.a = {}} { }
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %default.import = import <none>
 // CHECK:STDOUT:   %C3.decl: type = class_decl @C3 [template = constants.%C3] {} {}
-// CHECK:STDOUT:   impl_decl @impl [template] {} {
-// CHECK:STDOUT:     %C3.ref.loc5: type = name_ref C3, file.%C3.decl [template = constants.%C3]
-// CHECK:STDOUT:     %I.ref.loc5: type = name_ref I, imports.%Main.I [template = constants.%I.type]
+// CHECK:STDOUT:   impl_decl @impl.1 [template] {} {
+// CHECK:STDOUT:     %C3.ref: type = name_ref C3, file.%C3.decl [template = constants.%C3]
+// CHECK:STDOUT:     %I.ref: type = name_ref I, imports.%Main.I [template = constants.%I.type]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %impl_witness: <witness> = impl_witness (constants.%empty_struct_type) [template = constants.%impl_witness]
-// CHECK:STDOUT:   impl_decl @impl [template] {} {
-// CHECK:STDOUT:     %C3.ref.loc6: type = name_ref C3, file.%C3.decl [template = constants.%C3]
-// CHECK:STDOUT:     %I.ref.loc6: type = name_ref I, imports.%Main.I [template = constants.%I.type]
+// CHECK:STDOUT:   %impl_witness.loc9: <witness> = impl_witness (<error>) [template = constants.%impl_witness.85b]
+// CHECK:STDOUT:   impl_decl @impl.2 [template] {} {
+// CHECK:STDOUT:     %C3.ref: type = name_ref C3, file.%C3.decl [template = constants.%C3]
+// CHECK:STDOUT:     %I.ref: type = name_ref I, imports.%Main.I [template = constants.%I.type]
 // CHECK:STDOUT:     %.Self: %I.type = bind_symbolic_name .Self [symbolic = constants.%.Self]
 // CHECK:STDOUT:     %.Self.ref: %I.type = name_ref .Self, %.Self [symbolic = constants.%.Self]
 // CHECK:STDOUT:     %T.ref: %I.assoc_type = name_ref T, imports.%Main.import_ref.585 [template = constants.%assoc0]
 // CHECK:STDOUT:     %.Self.as_type: type = facet_access_type %.Self.ref [symbolic = constants.%.Self.as_type]
-// CHECK:STDOUT:     %.loc6_20: type = converted %.Self.ref, %.Self.as_type [symbolic = constants.%.Self.as_type]
+// CHECK:STDOUT:     %.loc10_20: type = converted %.Self.ref, %.Self.as_type [symbolic = constants.%.Self.as_type]
 // CHECK:STDOUT:     %.Self.as_wit: <witness> = facet_access_witness %.Self.ref [symbolic = constants.%.Self.as_wit]
 // CHECK:STDOUT:     %impl.elem0: type = impl_witness_access %.Self.as_wit, element0 [symbolic = constants.%impl.elem0]
-// CHECK:STDOUT:     %.loc6_26.1: %empty_struct_type = struct_literal ()
-// CHECK:STDOUT:     %.loc6_26.2: type = converted %.loc6_26.1, constants.%empty_struct_type [template = constants.%empty_struct_type]
-// CHECK:STDOUT:     %.loc6_14: type = where_expr %.Self [template = constants.%I_where.type] {
-// CHECK:STDOUT:       requirement_rewrite %impl.elem0, %.loc6_26.2
+// CHECK:STDOUT:     %.loc10_26.1: %empty_struct_type = struct_literal ()
+// CHECK:STDOUT:     %.loc10_26.2: type = converted %.loc10_26.1, constants.%empty_struct_type [template = constants.%empty_struct_type]
+// CHECK:STDOUT:     %.loc10_14: type = where_expr %.Self [template = constants.%I_where.type] {
+// CHECK:STDOUT:       requirement_rewrite %impl.elem0, %.loc10_26.2
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:   }
+// CHECK:STDOUT:   %impl_witness.loc10: <witness> = impl_witness (constants.%empty_struct_type) [template = constants.%impl_witness.6de]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @I [from "interface.carbon"] {
@@ -535,9 +547,11 @@ impl CC as NonType where .Y = {.a = {}} { }
 // CHECK:STDOUT:   assoc_const T:! type;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C3.ref.loc5 as %I.ref.loc5 {
+// CHECK:STDOUT: impl @impl.1: %C3.ref as %I.ref;
+// CHECK:STDOUT:
+// CHECK:STDOUT: impl @impl.2: %C3.ref as %.loc10_14 {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   witness = file.%impl_witness
+// CHECK:STDOUT:   witness = file.%impl_witness.loc10
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C3 {
@@ -569,8 +583,9 @@ impl CC as NonType where .Y = {.a = {}} { }
 // CHECK:STDOUT:   %I.facet: %I.type = facet_value %.Self.as_type, %.Self.as_wit [symbolic]
 // CHECK:STDOUT:   %impl.elem0: type = impl_witness_access %.Self.as_wit, element0 [symbolic]
 // CHECK:STDOUT:   %I_where.type.f5a: type = facet_type <@I where %impl.elem0 = %empty_struct_type> [template]
-// CHECK:STDOUT:   %impl_witness: <witness> = impl_witness (%empty_struct_type) [template]
+// CHECK:STDOUT:   %impl_witness.6de: <witness> = impl_witness (%empty_struct_type) [template]
 // CHECK:STDOUT:   %I_where.type.05a: type = facet_type <@I where %impl.elem0 = %empty_tuple.type> [template]
+// CHECK:STDOUT:   %impl_witness.2a6: <witness> = impl_witness (%empty_tuple.type) [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -591,39 +606,40 @@ impl CC as NonType where .Y = {.a = {}} { }
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %default.import = import <none>
 // CHECK:STDOUT:   %C4.decl: type = class_decl @C4 [template = constants.%C4] {} {}
-// CHECK:STDOUT:   impl_decl @impl [template] {} {
-// CHECK:STDOUT:     %C4.ref.loc5: type = name_ref C4, file.%C4.decl [template = constants.%C4]
-// CHECK:STDOUT:     %I.ref.loc5: type = name_ref I, imports.%Main.I [template = constants.%I.type]
-// CHECK:STDOUT:     %.Self.1: %I.type = bind_symbolic_name .Self [symbolic = constants.%.Self]
-// CHECK:STDOUT:     %.Self.ref.loc5: %I.type = name_ref .Self, %.Self.1 [symbolic = constants.%.Self]
-// CHECK:STDOUT:     %T.ref.loc5: %I.assoc_type = name_ref T, imports.%Main.import_ref.585 [template = constants.%assoc0]
-// CHECK:STDOUT:     %.Self.as_type.loc5: type = facet_access_type %.Self.ref.loc5 [symbolic = constants.%.Self.as_type]
-// CHECK:STDOUT:     %.loc5_20: type = converted %.Self.ref.loc5, %.Self.as_type.loc5 [symbolic = constants.%.Self.as_type]
-// CHECK:STDOUT:     %.Self.as_wit.loc5: <witness> = facet_access_witness %.Self.ref.loc5 [symbolic = constants.%.Self.as_wit]
-// CHECK:STDOUT:     %impl.elem0.loc5: type = impl_witness_access %.Self.as_wit.loc5, element0 [symbolic = constants.%impl.elem0]
-// CHECK:STDOUT:     %.loc5_26.1: %empty_struct_type = struct_literal ()
-// CHECK:STDOUT:     %.loc5_26.2: type = converted %.loc5_26.1, constants.%empty_struct_type [template = constants.%empty_struct_type]
-// CHECK:STDOUT:     %.loc5_14: type = where_expr %.Self.1 [template = constants.%I_where.type.f5a] {
-// CHECK:STDOUT:       requirement_rewrite %impl.elem0.loc5, %.loc5_26.2
+// CHECK:STDOUT:   impl_decl @impl.1 [template] {} {
+// CHECK:STDOUT:     %C4.ref: type = name_ref C4, file.%C4.decl [template = constants.%C4]
+// CHECK:STDOUT:     %I.ref: type = name_ref I, imports.%Main.I [template = constants.%I.type]
+// CHECK:STDOUT:     %.Self: %I.type = bind_symbolic_name .Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:     %.Self.ref: %I.type = name_ref .Self, %.Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:     %T.ref: %I.assoc_type = name_ref T, imports.%Main.import_ref.585 [template = constants.%assoc0]
+// CHECK:STDOUT:     %.Self.as_type: type = facet_access_type %.Self.ref [symbolic = constants.%.Self.as_type]
+// CHECK:STDOUT:     %.loc9_20: type = converted %.Self.ref, %.Self.as_type [symbolic = constants.%.Self.as_type]
+// CHECK:STDOUT:     %.Self.as_wit: <witness> = facet_access_witness %.Self.ref [symbolic = constants.%.Self.as_wit]
+// CHECK:STDOUT:     %impl.elem0: type = impl_witness_access %.Self.as_wit, element0 [symbolic = constants.%impl.elem0]
+// CHECK:STDOUT:     %.loc9_26.1: %empty_struct_type = struct_literal ()
+// CHECK:STDOUT:     %.loc9_26.2: type = converted %.loc9_26.1, constants.%empty_struct_type [template = constants.%empty_struct_type]
+// CHECK:STDOUT:     %.loc9_14: type = where_expr %.Self [template = constants.%I_where.type.f5a] {
+// CHECK:STDOUT:       requirement_rewrite %impl.elem0, %.loc9_26.2
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %impl_witness: <witness> = impl_witness (constants.%empty_struct_type) [template = constants.%impl_witness]
-// CHECK:STDOUT:   impl_decl @impl [template] {} {
-// CHECK:STDOUT:     %C4.ref.loc13: type = name_ref C4, file.%C4.decl [template = constants.%C4]
-// CHECK:STDOUT:     %I.ref.loc13: type = name_ref I, imports.%Main.I [template = constants.%I.type]
-// CHECK:STDOUT:     %.Self.2: %I.type = bind_symbolic_name .Self [symbolic = constants.%.Self]
-// CHECK:STDOUT:     %.Self.ref.loc13: %I.type = name_ref .Self, %.Self.2 [symbolic = constants.%.Self]
-// CHECK:STDOUT:     %T.ref.loc13: %I.assoc_type = name_ref T, imports.%Main.import_ref.585 [template = constants.%assoc0]
-// CHECK:STDOUT:     %.Self.as_type.loc13: type = facet_access_type %.Self.ref.loc13 [symbolic = constants.%.Self.as_type]
-// CHECK:STDOUT:     %.loc13_20: type = converted %.Self.ref.loc13, %.Self.as_type.loc13 [symbolic = constants.%.Self.as_type]
-// CHECK:STDOUT:     %.Self.as_wit.loc13: <witness> = facet_access_witness %.Self.ref.loc13 [symbolic = constants.%.Self.as_wit]
-// CHECK:STDOUT:     %impl.elem0.loc13: type = impl_witness_access %.Self.as_wit.loc13, element0 [symbolic = constants.%impl.elem0]
-// CHECK:STDOUT:     %.loc13_26.1: %empty_tuple.type = tuple_literal ()
-// CHECK:STDOUT:     %.loc13_26.2: type = converted %.loc13_26.1, constants.%empty_tuple.type [template = constants.%empty_tuple.type]
-// CHECK:STDOUT:     %.loc13_14: type = where_expr %.Self.2 [template = constants.%I_where.type.05a] {
-// CHECK:STDOUT:       requirement_rewrite %impl.elem0.loc13, %.loc13_26.2
+// CHECK:STDOUT:   %impl_witness.loc9: <witness> = impl_witness (constants.%empty_struct_type) [template = constants.%impl_witness.6de]
+// CHECK:STDOUT:   impl_decl @impl.2 [template] {} {
+// CHECK:STDOUT:     %C4.ref: type = name_ref C4, file.%C4.decl [template = constants.%C4]
+// CHECK:STDOUT:     %I.ref: type = name_ref I, imports.%Main.I [template = constants.%I.type]
+// CHECK:STDOUT:     %.Self: %I.type = bind_symbolic_name .Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:     %.Self.ref: %I.type = name_ref .Self, %.Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:     %T.ref: %I.assoc_type = name_ref T, imports.%Main.import_ref.585 [template = constants.%assoc0]
+// CHECK:STDOUT:     %.Self.as_type: type = facet_access_type %.Self.ref [symbolic = constants.%.Self.as_type]
+// CHECK:STDOUT:     %.loc10_20: type = converted %.Self.ref, %.Self.as_type [symbolic = constants.%.Self.as_type]
+// CHECK:STDOUT:     %.Self.as_wit: <witness> = facet_access_witness %.Self.ref [symbolic = constants.%.Self.as_wit]
+// CHECK:STDOUT:     %impl.elem0: type = impl_witness_access %.Self.as_wit, element0 [symbolic = constants.%impl.elem0]
+// CHECK:STDOUT:     %.loc10_26.1: %empty_tuple.type = tuple_literal ()
+// CHECK:STDOUT:     %.loc10_26.2: type = converted %.loc10_26.1, constants.%empty_tuple.type [template = constants.%empty_tuple.type]
+// CHECK:STDOUT:     %.loc10_14: type = where_expr %.Self [template = constants.%I_where.type.05a] {
+// CHECK:STDOUT:       requirement_rewrite %impl.elem0, %.loc10_26.2
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:   }
+// CHECK:STDOUT:   %impl_witness.loc10: <witness> = impl_witness (constants.%empty_tuple.type) [template = constants.%impl_witness.2a6]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @I [from "interface.carbon"] {
@@ -637,9 +653,11 @@ impl CC as NonType where .Y = {.a = {}} { }
 // CHECK:STDOUT:   assoc_const T:! type;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C4.ref.loc5 as %.loc5_14 {
+// CHECK:STDOUT: impl @impl.1: %C4.ref as %.loc9_14;
+// CHECK:STDOUT:
+// CHECK:STDOUT: impl @impl.2: %C4.ref as %.loc10_14 {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   witness = file.%impl_witness
+// CHECK:STDOUT:   witness = file.%impl_witness.loc10
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C4 {
@@ -699,70 +717,70 @@ impl CC as NonType where .Y = {.a = {}} { }
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %default.import = import <none>
 // CHECK:STDOUT:   %C5.decl: type = class_decl @C5 [template = constants.%C5] {} {}
-// CHECK:STDOUT:   impl_decl @impl [template] {} {
-// CHECK:STDOUT:     %C5.ref.loc18: type = name_ref C5, file.%C5.decl [template = constants.%C5]
-// CHECK:STDOUT:     %I3.ref.loc18: type = name_ref I3, imports.%Main.I3 [template = constants.%I3.type]
-// CHECK:STDOUT:     %.Self.1: %I3.type = bind_symbolic_name .Self [symbolic = constants.%.Self]
-// CHECK:STDOUT:     %.Self.ref.loc18_21: %I3.type = name_ref .Self, %.Self.1 [symbolic = constants.%.Self]
-// CHECK:STDOUT:     %T1.ref.loc18: %I3.assoc_type = name_ref T1, imports.%Main.import_ref.760 [template = constants.%assoc0]
+// CHECK:STDOUT:   impl_decl @impl.1 [template] {} {
+// CHECK:STDOUT:     %C5.ref: type = name_ref C5, file.%C5.decl [template = constants.%C5]
+// CHECK:STDOUT:     %I3.ref: type = name_ref I3, imports.%Main.I3 [template = constants.%I3.type]
+// CHECK:STDOUT:     %.Self: %I3.type = bind_symbolic_name .Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:     %.Self.ref.loc18_21: %I3.type = name_ref .Self, %.Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:     %T1.ref: %I3.assoc_type = name_ref T1, imports.%Main.import_ref.760 [template = constants.%assoc0]
 // CHECK:STDOUT:     %.Self.as_type.loc18_21: type = facet_access_type %.Self.ref.loc18_21 [symbolic = constants.%.Self.as_type]
 // CHECK:STDOUT:     %.loc18_21: type = converted %.Self.ref.loc18_21, %.Self.as_type.loc18_21 [symbolic = constants.%.Self.as_type]
 // CHECK:STDOUT:     %.Self.as_wit.loc18_21: <witness> = facet_access_witness %.Self.ref.loc18_21 [symbolic = constants.%.Self.as_wit]
-// CHECK:STDOUT:     %impl.elem0.loc18: type = impl_witness_access %.Self.as_wit.loc18_21, element0 [symbolic = constants.%impl.elem0]
+// CHECK:STDOUT:     %impl.elem0: type = impl_witness_access %.Self.as_wit.loc18_21, element0 [symbolic = constants.%impl.elem0]
 // CHECK:STDOUT:     %BAD1.ref: <error> = name_ref BAD1, <error> [template = <error>]
-// CHECK:STDOUT:     %.Self.ref.loc18_36: %I3.type = name_ref .Self, %.Self.1 [symbolic = constants.%.Self]
-// CHECK:STDOUT:     %T2.ref.loc18: %I3.assoc_type = name_ref T2, imports.%Main.import_ref.309 [template = constants.%assoc1]
+// CHECK:STDOUT:     %.Self.ref.loc18_36: %I3.type = name_ref .Self, %.Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:     %T2.ref: %I3.assoc_type = name_ref T2, imports.%Main.import_ref.309 [template = constants.%assoc1]
 // CHECK:STDOUT:     %.Self.as_type.loc18_36: type = facet_access_type %.Self.ref.loc18_36 [symbolic = constants.%.Self.as_type]
 // CHECK:STDOUT:     %.loc18_36: type = converted %.Self.ref.loc18_36, %.Self.as_type.loc18_36 [symbolic = constants.%.Self.as_type]
 // CHECK:STDOUT:     %.Self.as_wit.loc18_36: <witness> = facet_access_witness %.Self.ref.loc18_36 [symbolic = constants.%.Self.as_wit]
-// CHECK:STDOUT:     %impl.elem1.loc18: type = impl_witness_access %.Self.as_wit.loc18_36, element1 [symbolic = constants.%impl.elem1]
+// CHECK:STDOUT:     %impl.elem1: type = impl_witness_access %.Self.as_wit.loc18_36, element1 [symbolic = constants.%impl.elem1]
 // CHECK:STDOUT:     %.loc18_48.1: %empty_struct_type = struct_literal ()
 // CHECK:STDOUT:     %.loc18_48.2: type = converted %.loc18_48.1, constants.%empty_struct_type [template = constants.%empty_struct_type]
 // CHECK:STDOUT:     %struct_type.a: type = struct_type {.a: %empty_struct_type} [template = constants.%struct_type.a]
-// CHECK:STDOUT:     %.Self.ref.loc18_55: %I3.type = name_ref .Self, %.Self.1 [symbolic = constants.%.Self]
-// CHECK:STDOUT:     %T3.ref.loc18: %I3.assoc_type = name_ref T3, imports.%Main.import_ref.5c5 [template = constants.%assoc2]
+// CHECK:STDOUT:     %.Self.ref.loc18_55: %I3.type = name_ref .Self, %.Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:     %T3.ref: %I3.assoc_type = name_ref T3, imports.%Main.import_ref.5c5 [template = constants.%assoc2]
 // CHECK:STDOUT:     %.Self.as_type.loc18_55: type = facet_access_type %.Self.ref.loc18_55 [symbolic = constants.%.Self.as_type]
 // CHECK:STDOUT:     %.loc18_55: type = converted %.Self.ref.loc18_55, %.Self.as_type.loc18_55 [symbolic = constants.%.Self.as_type]
 // CHECK:STDOUT:     %.Self.as_wit.loc18_55: <witness> = facet_access_witness %.Self.ref.loc18_55 [symbolic = constants.%.Self.as_wit]
-// CHECK:STDOUT:     %impl.elem2.loc18: type = impl_witness_access %.Self.as_wit.loc18_55, element2 [symbolic = constants.%impl.elem2]
+// CHECK:STDOUT:     %impl.elem2: type = impl_witness_access %.Self.as_wit.loc18_55, element2 [symbolic = constants.%impl.elem2]
 // CHECK:STDOUT:     %BAD2.ref: <error> = name_ref BAD2, <error> [template = <error>]
-// CHECK:STDOUT:     %.loc18_15: type = where_expr %.Self.1 [template = <error>] {
-// CHECK:STDOUT:       requirement_rewrite %impl.elem0.loc18, <error>
-// CHECK:STDOUT:       requirement_rewrite %impl.elem1.loc18, %struct_type.a
-// CHECK:STDOUT:       requirement_rewrite %impl.elem2.loc18, <error>
+// CHECK:STDOUT:     %.loc18_15: type = where_expr %.Self [template = <error>] {
+// CHECK:STDOUT:       requirement_rewrite %impl.elem0, <error>
+// CHECK:STDOUT:       requirement_rewrite %impl.elem1, %struct_type.a
+// CHECK:STDOUT:       requirement_rewrite %impl.elem2, <error>
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   impl_decl @impl [template] {} {
-// CHECK:STDOUT:     %C5.ref.loc28: type = name_ref C5, file.%C5.decl [template = constants.%C5]
-// CHECK:STDOUT:     %I3.ref.loc28: type = name_ref I3, imports.%Main.I3 [template = constants.%I3.type]
-// CHECK:STDOUT:     %.Self.2: %I3.type = bind_symbolic_name .Self [symbolic = constants.%.Self]
-// CHECK:STDOUT:     %.Self.ref.loc28_21: %I3.type = name_ref .Self, %.Self.2 [symbolic = constants.%.Self]
-// CHECK:STDOUT:     %T1.ref.loc28: %I3.assoc_type = name_ref T1, imports.%Main.import_ref.760 [template = constants.%assoc0]
-// CHECK:STDOUT:     %.Self.as_type.loc28_21: type = facet_access_type %.Self.ref.loc28_21 [symbolic = constants.%.Self.as_type]
-// CHECK:STDOUT:     %.loc28_21: type = converted %.Self.ref.loc28_21, %.Self.as_type.loc28_21 [symbolic = constants.%.Self.as_type]
-// CHECK:STDOUT:     %.Self.as_wit.loc28_21: <witness> = facet_access_witness %.Self.ref.loc28_21 [symbolic = constants.%.Self.as_wit]
-// CHECK:STDOUT:     %impl.elem0.loc28: type = impl_witness_access %.Self.as_wit.loc28_21, element0 [symbolic = constants.%impl.elem0]
-// CHECK:STDOUT:     %.loc28_33.1: %empty_struct_type = struct_literal ()
-// CHECK:STDOUT:     %.loc28_33.2: type = converted %.loc28_33.1, constants.%empty_struct_type [template = constants.%empty_struct_type]
+// CHECK:STDOUT:   impl_decl @impl.2 [template] {} {
+// CHECK:STDOUT:     %C5.ref: type = name_ref C5, file.%C5.decl [template = constants.%C5]
+// CHECK:STDOUT:     %I3.ref: type = name_ref I3, imports.%Main.I3 [template = constants.%I3.type]
+// CHECK:STDOUT:     %.Self: %I3.type = bind_symbolic_name .Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:     %.Self.ref.loc32_21: %I3.type = name_ref .Self, %.Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:     %T1.ref: %I3.assoc_type = name_ref T1, imports.%Main.import_ref.760 [template = constants.%assoc0]
+// CHECK:STDOUT:     %.Self.as_type.loc32_21: type = facet_access_type %.Self.ref.loc32_21 [symbolic = constants.%.Self.as_type]
+// CHECK:STDOUT:     %.loc32_21: type = converted %.Self.ref.loc32_21, %.Self.as_type.loc32_21 [symbolic = constants.%.Self.as_type]
+// CHECK:STDOUT:     %.Self.as_wit.loc32_21: <witness> = facet_access_witness %.Self.ref.loc32_21 [symbolic = constants.%.Self.as_wit]
+// CHECK:STDOUT:     %impl.elem0: type = impl_witness_access %.Self.as_wit.loc32_21, element0 [symbolic = constants.%impl.elem0]
+// CHECK:STDOUT:     %.loc32_33.1: %empty_struct_type = struct_literal ()
+// CHECK:STDOUT:     %.loc32_33.2: type = converted %.loc32_33.1, constants.%empty_struct_type [template = constants.%empty_struct_type]
 // CHECK:STDOUT:     %struct_type.b: type = struct_type {.b: %empty_struct_type} [template = constants.%struct_type.b]
-// CHECK:STDOUT:     %.Self.ref.loc28_40: %I3.type = name_ref .Self, %.Self.2 [symbolic = constants.%.Self]
-// CHECK:STDOUT:     %T2.ref.loc28: %I3.assoc_type = name_ref T2, imports.%Main.import_ref.309 [template = constants.%assoc1]
-// CHECK:STDOUT:     %.Self.as_type.loc28_40: type = facet_access_type %.Self.ref.loc28_40 [symbolic = constants.%.Self.as_type]
-// CHECK:STDOUT:     %.loc28_40: type = converted %.Self.ref.loc28_40, %.Self.as_type.loc28_40 [symbolic = constants.%.Self.as_type]
-// CHECK:STDOUT:     %.Self.as_wit.loc28_40: <witness> = facet_access_witness %.Self.ref.loc28_40 [symbolic = constants.%.Self.as_wit]
-// CHECK:STDOUT:     %impl.elem1.loc28: type = impl_witness_access %.Self.as_wit.loc28_40, element1 [symbolic = constants.%impl.elem1]
+// CHECK:STDOUT:     %.Self.ref.loc32_40: %I3.type = name_ref .Self, %.Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:     %T2.ref: %I3.assoc_type = name_ref T2, imports.%Main.import_ref.309 [template = constants.%assoc1]
+// CHECK:STDOUT:     %.Self.as_type.loc32_40: type = facet_access_type %.Self.ref.loc32_40 [symbolic = constants.%.Self.as_type]
+// CHECK:STDOUT:     %.loc32_40: type = converted %.Self.ref.loc32_40, %.Self.as_type.loc32_40 [symbolic = constants.%.Self.as_type]
+// CHECK:STDOUT:     %.Self.as_wit.loc32_40: <witness> = facet_access_witness %.Self.ref.loc32_40 [symbolic = constants.%.Self.as_wit]
+// CHECK:STDOUT:     %impl.elem1: type = impl_witness_access %.Self.as_wit.loc32_40, element1 [symbolic = constants.%impl.elem1]
 // CHECK:STDOUT:     %BAD3.ref: <error> = name_ref BAD3, <error> [template = <error>]
-// CHECK:STDOUT:     %.Self.ref.loc28_55: %I3.type = name_ref .Self, %.Self.2 [symbolic = constants.%.Self]
-// CHECK:STDOUT:     %T3.ref.loc28: %I3.assoc_type = name_ref T3, imports.%Main.import_ref.5c5 [template = constants.%assoc2]
-// CHECK:STDOUT:     %.Self.as_type.loc28_55: type = facet_access_type %.Self.ref.loc28_55 [symbolic = constants.%.Self.as_type]
-// CHECK:STDOUT:     %.loc28_55: type = converted %.Self.ref.loc28_55, %.Self.as_type.loc28_55 [symbolic = constants.%.Self.as_type]
-// CHECK:STDOUT:     %.Self.as_wit.loc28_55: <witness> = facet_access_witness %.Self.ref.loc28_55 [symbolic = constants.%.Self.as_wit]
-// CHECK:STDOUT:     %impl.elem2.loc28: type = impl_witness_access %.Self.as_wit.loc28_55, element2 [symbolic = constants.%impl.elem2]
+// CHECK:STDOUT:     %.Self.ref.loc32_55: %I3.type = name_ref .Self, %.Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:     %T3.ref: %I3.assoc_type = name_ref T3, imports.%Main.import_ref.5c5 [template = constants.%assoc2]
+// CHECK:STDOUT:     %.Self.as_type.loc32_55: type = facet_access_type %.Self.ref.loc32_55 [symbolic = constants.%.Self.as_type]
+// CHECK:STDOUT:     %.loc32_55: type = converted %.Self.ref.loc32_55, %.Self.as_type.loc32_55 [symbolic = constants.%.Self.as_type]
+// CHECK:STDOUT:     %.Self.as_wit.loc32_55: <witness> = facet_access_witness %.Self.ref.loc32_55 [symbolic = constants.%.Self.as_wit]
+// CHECK:STDOUT:     %impl.elem2: type = impl_witness_access %.Self.as_wit.loc32_55, element2 [symbolic = constants.%impl.elem2]
 // CHECK:STDOUT:     %BAD4.ref: <error> = name_ref BAD4, <error> [template = <error>]
-// CHECK:STDOUT:     %.loc28_15: type = where_expr %.Self.2 [template = <error>] {
-// CHECK:STDOUT:       requirement_rewrite %impl.elem0.loc28, %struct_type.b
-// CHECK:STDOUT:       requirement_rewrite %impl.elem1.loc28, <error>
-// CHECK:STDOUT:       requirement_rewrite %impl.elem2.loc28, <error>
+// CHECK:STDOUT:     %.loc32_15: type = where_expr %.Self [template = <error>] {
+// CHECK:STDOUT:       requirement_rewrite %impl.elem0, %struct_type.b
+// CHECK:STDOUT:       requirement_rewrite %impl.elem1, <error>
+// CHECK:STDOUT:       requirement_rewrite %impl.elem2, <error>
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
@@ -788,7 +806,9 @@ impl CC as NonType where .Y = {.a = {}} { }
 // CHECK:STDOUT:   assoc_const T3:! type;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C5.ref.loc18 as %.loc18_15 {
+// CHECK:STDOUT: impl @impl.1: %C5.ref as %.loc18_15;
+// CHECK:STDOUT:
+// CHECK:STDOUT: impl @impl.2: %C5.ref as %.loc32_15 {
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   witness = <error>
 // CHECK:STDOUT: }
@@ -829,7 +849,8 @@ impl CC as NonType where .Y = {.a = {}} { }
 // CHECK:STDOUT:   %I.facet: %I.type = facet_value %.Self.as_type, %.Self.as_wit [symbolic]
 // CHECK:STDOUT:   %impl.elem0: type = impl_witness_access %.Self.as_wit, element0 [symbolic]
 // CHECK:STDOUT:   %I_where.type: type = facet_type <@I where %impl.elem0 = %empty_struct_type> [template]
-// CHECK:STDOUT:   %impl_witness: <witness> = impl_witness (%empty_struct_type) [template]
+// CHECK:STDOUT:   %impl_witness.6de: <witness> = impl_witness (%empty_struct_type) [template]
+// CHECK:STDOUT:   %impl_witness.85b: <witness> = impl_witness (<error>) [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -850,9 +871,9 @@ impl CC as NonType where .Y = {.a = {}} { }
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %default.import = import <none>
 // CHECK:STDOUT:   %C6.decl: type = class_decl @C6 [template = constants.%C6] {} {}
-// CHECK:STDOUT:   impl_decl @impl [template] {} {
-// CHECK:STDOUT:     %C6.ref.loc5: type = name_ref C6, file.%C6.decl [template = constants.%C6]
-// CHECK:STDOUT:     %I.ref.loc5: type = name_ref I, imports.%Main.I [template = constants.%I.type]
+// CHECK:STDOUT:   impl_decl @impl.1 [template] {} {
+// CHECK:STDOUT:     %C6.ref: type = name_ref C6, file.%C6.decl [template = constants.%C6]
+// CHECK:STDOUT:     %I.ref: type = name_ref I, imports.%Main.I [template = constants.%I.type]
 // CHECK:STDOUT:     %.Self: %I.type = bind_symbolic_name .Self [symbolic = constants.%.Self]
 // CHECK:STDOUT:     %.Self.ref: %I.type = name_ref .Self, %.Self [symbolic = constants.%.Self]
 // CHECK:STDOUT:     %T.ref: %I.assoc_type = name_ref T, imports.%Main.import_ref.585 [template = constants.%assoc0]
@@ -866,11 +887,12 @@ impl CC as NonType where .Y = {.a = {}} { }
 // CHECK:STDOUT:       requirement_rewrite %impl.elem0, %.loc5_26.2
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %impl_witness: <witness> = impl_witness (constants.%empty_struct_type) [template = constants.%impl_witness]
-// CHECK:STDOUT:   impl_decl @impl [template] {} {
-// CHECK:STDOUT:     %C6.ref.loc13: type = name_ref C6, file.%C6.decl [template = constants.%C6]
-// CHECK:STDOUT:     %I.ref.loc13: type = name_ref I, imports.%Main.I [template = constants.%I.type]
+// CHECK:STDOUT:   %impl_witness.loc5: <witness> = impl_witness (constants.%empty_struct_type) [template = constants.%impl_witness.6de]
+// CHECK:STDOUT:   impl_decl @impl.2 [template] {} {
+// CHECK:STDOUT:     %C6.ref: type = name_ref C6, file.%C6.decl [template = constants.%C6]
+// CHECK:STDOUT:     %I.ref: type = name_ref I, imports.%Main.I [template = constants.%I.type]
 // CHECK:STDOUT:   }
+// CHECK:STDOUT:   %impl_witness.loc18: <witness> = impl_witness (<error>) [template = constants.%impl_witness.85b]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @I [from "interface.carbon"] {
@@ -884,9 +906,11 @@ impl CC as NonType where .Y = {.a = {}} { }
 // CHECK:STDOUT:   assoc_const T:! type;
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl: %C6.ref.loc5 as %.loc5_14 {
+// CHECK:STDOUT: impl @impl.1: %C6.ref as %.loc5_14;
+// CHECK:STDOUT:
+// CHECK:STDOUT: impl @impl.2: %C6.ref as %I.ref {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   witness = file.%impl_witness
+// CHECK:STDOUT:   witness = file.%impl_witness.loc18
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C6 {

+ 0 - 3
toolchain/diagnostics/diagnostic_kind.def

@@ -256,9 +256,7 @@ CARBON_DIAGNOSTIC_KIND(InterfaceForwardDeclaredHere)
 CARBON_DIAGNOSTIC_KIND(InterfaceUndefinedWithinDefinition)
 
 // Impl checking.
-CARBON_DIAGNOSTIC_KIND(AssociatedConstantDifferentInRedecl)
 CARBON_DIAGNOSTIC_KIND(AssociatedConstantHere)
-CARBON_DIAGNOSTIC_KIND(AssociatedConstantMissingInRedecl)
 CARBON_DIAGNOSTIC_KIND(AssociatedConstantNotConstantAfterConversion)
 CARBON_DIAGNOSTIC_KIND(AssociatedFunctionHere)
 CARBON_DIAGNOSTIC_KIND(ExtendImplForall)
@@ -273,7 +271,6 @@ CARBON_DIAGNOSTIC_KIND(ImplFunctionWithNonFunction)
 CARBON_DIAGNOSTIC_KIND(ImplMissingDefinition)
 CARBON_DIAGNOSTIC_KIND(ImplMissingFunction)
 CARBON_DIAGNOSTIC_KIND(ImplPreviousDefinition)
-CARBON_DIAGNOSTIC_KIND(ImplPreviousDeclHere)
 CARBON_DIAGNOSTIC_KIND(ImplRedefinition)
 CARBON_DIAGNOSTIC_KIND(ImplOfUndefinedInterface)
 

+ 65 - 0
toolchain/parse/testdata/where_expr/impl_where.carbon

@@ -17,6 +17,13 @@ impl i32 as Interface where .T = () {
 
 impl bool as Interface where .T = i32;
 
+impl () as (Interface where .T = {}) {}
+
+impl {} as (Interface where .T = ()) where .T = ();
+
+impl f64 as Interface where .T = (type where .Self impls type) {
+}
+
 // CHECK:STDOUT: - filename: impl_where.carbon
 // CHECK:STDOUT:   parse_tree: [
 // CHECK:STDOUT:     {kind: 'FileStart', text: ''},
@@ -53,5 +60,63 @@ impl bool as Interface where .T = i32;
 // CHECK:STDOUT:         {kind: 'RequirementEqual', text: '=', subtree_size: 4},
 // CHECK:STDOUT:       {kind: 'WhereExpr', text: 'where', subtree_size: 7},
 // CHECK:STDOUT:     {kind: 'ImplDecl', text: ';', subtree_size: 11},
+// CHECK:STDOUT:         {kind: 'ImplIntroducer', text: 'impl'},
+// CHECK:STDOUT:             {kind: 'TupleLiteralStart', text: '('},
+// CHECK:STDOUT:           {kind: 'TupleLiteral', text: ')', subtree_size: 2},
+// CHECK:STDOUT:         {kind: 'TypeImplAs', text: 'as', subtree_size: 3},
+// CHECK:STDOUT:           {kind: 'ParenExprStart', text: '('},
+// CHECK:STDOUT:               {kind: 'IdentifierNameExpr', text: 'Interface'},
+// CHECK:STDOUT:             {kind: 'WhereOperand', text: 'where', subtree_size: 2},
+// CHECK:STDOUT:                 {kind: 'IdentifierNameNotBeforeParams', text: 'T'},
+// CHECK:STDOUT:               {kind: 'DesignatorExpr', text: '.', subtree_size: 2},
+// CHECK:STDOUT:                 {kind: 'StructLiteralStart', text: '{'},
+// CHECK:STDOUT:               {kind: 'StructLiteral', text: '}', subtree_size: 2},
+// CHECK:STDOUT:             {kind: 'RequirementEqual', text: '=', subtree_size: 5},
+// CHECK:STDOUT:           {kind: 'WhereExpr', text: 'where', subtree_size: 8},
+// CHECK:STDOUT:         {kind: 'ParenExpr', text: ')', subtree_size: 10},
+// CHECK:STDOUT:       {kind: 'ImplDefinitionStart', text: '{', subtree_size: 15},
+// CHECK:STDOUT:     {kind: 'ImplDefinition', text: '}', subtree_size: 16},
+// CHECK:STDOUT:       {kind: 'ImplIntroducer', text: 'impl'},
+// CHECK:STDOUT:           {kind: 'StructLiteralStart', text: '{'},
+// CHECK:STDOUT:         {kind: 'StructLiteral', text: '}', subtree_size: 2},
+// CHECK:STDOUT:       {kind: 'TypeImplAs', text: 'as', subtree_size: 3},
+// CHECK:STDOUT:             {kind: 'ParenExprStart', text: '('},
+// CHECK:STDOUT:                 {kind: 'IdentifierNameExpr', text: 'Interface'},
+// CHECK:STDOUT:               {kind: 'WhereOperand', text: 'where', subtree_size: 2},
+// CHECK:STDOUT:                   {kind: 'IdentifierNameNotBeforeParams', text: 'T'},
+// CHECK:STDOUT:                 {kind: 'DesignatorExpr', text: '.', subtree_size: 2},
+// CHECK:STDOUT:                   {kind: 'TupleLiteralStart', text: '('},
+// CHECK:STDOUT:                 {kind: 'TupleLiteral', text: ')', subtree_size: 2},
+// CHECK:STDOUT:               {kind: 'RequirementEqual', text: '=', subtree_size: 5},
+// CHECK:STDOUT:             {kind: 'WhereExpr', text: 'where', subtree_size: 8},
+// CHECK:STDOUT:           {kind: 'ParenExpr', text: ')', subtree_size: 10},
+// CHECK:STDOUT:         {kind: 'WhereOperand', text: 'where', subtree_size: 11},
+// CHECK:STDOUT:             {kind: 'IdentifierNameNotBeforeParams', text: 'T'},
+// CHECK:STDOUT:           {kind: 'DesignatorExpr', text: '.', subtree_size: 2},
+// CHECK:STDOUT:             {kind: 'TupleLiteralStart', text: '('},
+// CHECK:STDOUT:           {kind: 'TupleLiteral', text: ')', subtree_size: 2},
+// CHECK:STDOUT:         {kind: 'RequirementEqual', text: '=', subtree_size: 5},
+// CHECK:STDOUT:       {kind: 'WhereExpr', text: 'where', subtree_size: 17},
+// CHECK:STDOUT:     {kind: 'ImplDecl', text: ';', subtree_size: 22},
+// CHECK:STDOUT:         {kind: 'ImplIntroducer', text: 'impl'},
+// CHECK:STDOUT:           {kind: 'FloatTypeLiteral', text: 'f64'},
+// CHECK:STDOUT:         {kind: 'TypeImplAs', text: 'as', subtree_size: 2},
+// CHECK:STDOUT:             {kind: 'IdentifierNameExpr', text: 'Interface'},
+// CHECK:STDOUT:           {kind: 'WhereOperand', text: 'where', subtree_size: 2},
+// CHECK:STDOUT:               {kind: 'IdentifierNameNotBeforeParams', text: 'T'},
+// CHECK:STDOUT:             {kind: 'DesignatorExpr', text: '.', subtree_size: 2},
+// CHECK:STDOUT:               {kind: 'ParenExprStart', text: '('},
+// CHECK:STDOUT:                   {kind: 'TypeTypeLiteral', text: 'type'},
+// CHECK:STDOUT:                 {kind: 'WhereOperand', text: 'where', subtree_size: 2},
+// CHECK:STDOUT:                     {kind: 'SelfTypeName', text: 'Self'},
+// CHECK:STDOUT:                   {kind: 'DesignatorExpr', text: '.', subtree_size: 2},
+// CHECK:STDOUT:                   {kind: 'TypeTypeLiteral', text: 'type'},
+// CHECK:STDOUT:                 {kind: 'RequirementImpls', text: 'impls', subtree_size: 4},
+// CHECK:STDOUT:               {kind: 'WhereExpr', text: 'where', subtree_size: 7},
+// CHECK:STDOUT:             {kind: 'ParenExpr', text: ')', subtree_size: 9},
+// CHECK:STDOUT:           {kind: 'RequirementEqual', text: '=', subtree_size: 12},
+// CHECK:STDOUT:         {kind: 'WhereExpr', text: 'where', subtree_size: 15},
+// CHECK:STDOUT:       {kind: 'ImplDefinitionStart', text: '{', subtree_size: 19},
+// CHECK:STDOUT:     {kind: 'ImplDefinition', text: '}', subtree_size: 20},
 // CHECK:STDOUT:     {kind: 'FileEnd', text: ''},
 // CHECK:STDOUT:   ]