Procházet zdrojové kódy

Implement syntactic merge checks for parameters. (#4149)

Note this isn't implementing checking through imports. The parse node
there is harder to access through the context, so would require
examining the entity in order to get the import declaration, to get at
the ImportIR. We also don't have a parse tree attached in that case, and
would need to add one to SemIR::File. But I believe we do want to add
that, so it's explicitly a TODO.

Note GetTokenText re-lexes literal values, so there's a bit of potential
overhead there. Not sure if we want a more efficient manner for
comparing in cases like this.
Jon Ross-Perkins před 1 rokem
rodič
revize
db022658c6

+ 8 - 6
toolchain/check/decl_name_stack.cpp

@@ -366,8 +366,9 @@ auto DeclNameStack::ResolveAsScope(const NameContext& name_context,
     return InvalidResult;
     return InvalidResult;
   }
   }
 
 
-  auto new_params =
-      DeclParams(name.name_loc_id, name.implicit_params_id, name.params_id);
+  auto new_params = DeclParams(name.name_loc_id, name.first_param_node_id,
+                               name.last_param_node_id, name.implicit_params_id,
+                               name.params_id);
 
 
   // Find the scope corresponding to the resolved instruction.
   // Find the scope corresponding to the resolved instruction.
   CARBON_KIND_SWITCH(context_->insts().Get(name_context.resolved_inst_id)) {
   CARBON_KIND_SWITCH(context_->insts().Get(name_context.resolved_inst_id)) {
@@ -404,10 +405,11 @@ auto DeclNameStack::ResolveAsScope(const NameContext& name_context,
     case CARBON_KIND(SemIR::Namespace resolved_inst): {
     case CARBON_KIND(SemIR::Namespace resolved_inst): {
       auto scope_id = resolved_inst.name_scope_id;
       auto scope_id = resolved_inst.name_scope_id;
       auto& scope = context_->name_scopes().Get(scope_id);
       auto& scope = context_->name_scopes().Get(scope_id);
-      if (!CheckRedeclParamsMatch(*context_, new_params,
-                                  DeclParams(name_context.resolved_inst_id,
-                                             SemIR::InstBlockId::Invalid,
-                                             SemIR::InstBlockId::Invalid))) {
+      if (!CheckRedeclParamsMatch(
+              *context_, new_params,
+              DeclParams(name_context.resolved_inst_id, Parse::NodeId::Invalid,
+                         Parse::NodeId::Invalid, SemIR::InstBlockId::Invalid,
+                         SemIR::InstBlockId::Invalid))) {
         return InvalidResult;
         return InvalidResult;
       }
       }
       if (scope.is_closed_import) {
       if (scope.is_closed_import) {

+ 4 - 2
toolchain/check/function.cpp

@@ -13,9 +13,11 @@ namespace Carbon::Check {
 auto CheckFunctionTypeMatches(Context& context,
 auto CheckFunctionTypeMatches(Context& context,
                               const SemIR::Function& new_function,
                               const SemIR::Function& new_function,
                               const SemIR::Function& prev_function,
                               const SemIR::Function& prev_function,
-                              Substitutions substitutions) -> bool {
+                              Substitutions substitutions, bool check_syntax)
+    -> bool {
   if (!CheckRedeclParamsMatch(context, DeclParams(new_function),
   if (!CheckRedeclParamsMatch(context, DeclParams(new_function),
-                              DeclParams(prev_function), substitutions)) {
+                              DeclParams(prev_function), substitutions,
+                              check_syntax)) {
     return false;
     return false;
   }
   }
 
 

+ 2 - 3
toolchain/check/function.h

@@ -29,12 +29,11 @@ struct SuspendedFunction {
 // Checks that `new_function` has the same parameter types and return type as
 // Checks that `new_function` has the same parameter types and return type as
 // `prev_function`, applying the specified set of substitutions to the
 // `prev_function`, applying the specified set of substitutions to the
 // previous function. Prints a suitable diagnostic and returns false if not.
 // previous function. Prints a suitable diagnostic and returns false if not.
-// Note that this doesn't include the syntactic check that's performed for
-// redeclarations.
 auto CheckFunctionTypeMatches(Context& context,
 auto CheckFunctionTypeMatches(Context& context,
                               const SemIR::Function& new_function,
                               const SemIR::Function& new_function,
                               const SemIR::Function& prev_function,
                               const SemIR::Function& prev_function,
-                              Substitutions substitutions) -> bool;
+                              Substitutions substitutions, bool check_syntax)
+    -> bool;
 
 
 // Checks that the return type of the specified function is complete, issuing an
 // Checks that the return type of the specified function is complete, issuing an
 // error if not. This computes the return slot usage for the function if
 // error if not. This computes the return slot usage for the function if

+ 2 - 0
toolchain/check/global_init.cpp

@@ -39,6 +39,8 @@ auto GlobalInit::Finalize() -> void {
        .parent_scope_id = SemIR::NameScopeId::Package,
        .parent_scope_id = SemIR::NameScopeId::Package,
        .decl_id = SemIR::InstId::Invalid,
        .decl_id = SemIR::InstId::Invalid,
        .generic_id = SemIR::GenericId::Invalid,
        .generic_id = SemIR::GenericId::Invalid,
+       .first_param_node_id = Parse::NodeId::Invalid,
+       .last_param_node_id = Parse::NodeId::Invalid,
        .implicit_param_refs_id = SemIR::InstBlockId::Invalid,
        .implicit_param_refs_id = SemIR::InstBlockId::Invalid,
        .param_refs_id = SemIR::InstBlockId::Empty,
        .param_refs_id = SemIR::InstBlockId::Empty,
        .return_storage_id = SemIR::InstId::Invalid,
        .return_storage_id = SemIR::InstId::Invalid,

+ 4 - 0
toolchain/check/handle_class.cpp

@@ -93,6 +93,8 @@ static auto MergeClassRedecl(Context& context, SemIRLoc new_loc,
   }
   }
 
 
   if (new_is_definition) {
   if (new_is_definition) {
+    prev_class.first_param_node_id = new_class.first_param_node_id;
+    prev_class.last_param_node_id = new_class.last_param_node_id;
     prev_class.implicit_param_refs_id = new_class.implicit_param_refs_id;
     prev_class.implicit_param_refs_id = new_class.implicit_param_refs_id;
     prev_class.param_refs_id = new_class.param_refs_id;
     prev_class.param_refs_id = new_class.param_refs_id;
     prev_class.definition_id = new_class.definition_id;
     prev_class.definition_id = new_class.definition_id;
@@ -225,6 +227,8 @@ static auto BuildClassDecl(Context& context, Parse::AnyClassDeclId node_id,
       .name_id = name_context.name_id_for_new_inst(),
       .name_id = name_context.name_id_for_new_inst(),
       .parent_scope_id = name_context.parent_scope_id_for_new_inst(),
       .parent_scope_id = name_context.parent_scope_id_for_new_inst(),
       .generic_id = SemIR::GenericId::Invalid,
       .generic_id = SemIR::GenericId::Invalid,
+      .first_param_node_id = name.first_param_node_id,
+      .last_param_node_id = name.last_param_node_id,
       .implicit_param_refs_id = name.implicit_params_id,
       .implicit_param_refs_id = name.implicit_params_id,
       .param_refs_id = name.params_id,
       .param_refs_id = name.params_id,
       // `.self_type_id` depends on the ClassType, so is set below.
       // `.self_type_id` depends on the ClassType, so is set below.

+ 6 - 1
toolchain/check/handle_function.cpp

@@ -99,7 +99,8 @@ static auto MergeFunctionRedecl(Context& context, SemIRLoc new_loc,
                                 SemIR::ImportIRId prev_import_ir_id) -> bool {
                                 SemIR::ImportIRId prev_import_ir_id) -> bool {
   auto& prev_function = context.functions().Get(prev_function_id);
   auto& prev_function = context.functions().Get(prev_function_id);
 
 
-  if (!CheckFunctionTypeMatches(context, new_function, prev_function, {})) {
+  if (!CheckFunctionTypeMatches(context, new_function, prev_function, {},
+                                /*check_syntax=*/true)) {
     return false;
     return false;
   }
   }
 
 
@@ -118,6 +119,8 @@ static auto MergeFunctionRedecl(Context& context, SemIRLoc new_loc,
     // Track the signature from the definition, so that IDs in the body
     // Track the signature from the definition, so that IDs in the body
     // match IDs in the signature.
     // match IDs in the signature.
     prev_function.definition_id = new_function.definition_id;
     prev_function.definition_id = new_function.definition_id;
+    prev_function.first_param_node_id = new_function.first_param_node_id;
+    prev_function.last_param_node_id = new_function.last_param_node_id;
     prev_function.implicit_param_refs_id = new_function.implicit_param_refs_id;
     prev_function.implicit_param_refs_id = new_function.implicit_param_refs_id;
     prev_function.param_refs_id = new_function.param_refs_id;
     prev_function.param_refs_id = new_function.param_refs_id;
     prev_function.return_storage_id = new_function.return_storage_id;
     prev_function.return_storage_id = new_function.return_storage_id;
@@ -252,6 +255,8 @@ static auto BuildFunctionDecl(Context& context,
       .parent_scope_id = name_context.parent_scope_id_for_new_inst(),
       .parent_scope_id = name_context.parent_scope_id_for_new_inst(),
       .decl_id = decl_id,
       .decl_id = decl_id,
       .generic_id = SemIR::GenericId::Invalid,
       .generic_id = SemIR::GenericId::Invalid,
+      .first_param_node_id = name.first_param_node_id,
+      .last_param_node_id = name.last_param_node_id,
       .implicit_param_refs_id = name.implicit_params_id,
       .implicit_param_refs_id = name.implicit_params_id,
       .param_refs_id = name.params_id,
       .param_refs_id = name.params_id,
       .return_storage_id = return_storage_id,
       .return_storage_id = return_storage_id,

+ 2 - 0
toolchain/check/handle_impl.cpp

@@ -36,6 +36,8 @@ auto HandleParseNode(Context& context, Parse::ImplIntroducerId node_id)
 auto HandleParseNode(Context& context, Parse::ImplForallId node_id) -> bool {
 auto HandleParseNode(Context& context, Parse::ImplForallId node_id) -> bool {
   auto params_id =
   auto params_id =
       context.node_stack().Pop<Parse::NodeKind::ImplicitParamList>();
       context.node_stack().Pop<Parse::NodeKind::ImplicitParamList>();
+  context.node_stack()
+      .PopAndDiscardSoloNodeId<Parse::NodeKind::ImplicitParamListStart>();
   context.node_stack().Push(node_id, params_id);
   context.node_stack().Push(node_id, params_id);
   return true;
   return true;
 }
 }

+ 4 - 1
toolchain/check/handle_interface.cpp

@@ -62,7 +62,8 @@ static auto BuildInterfaceDecl(Context& context,
       // now we just check the generic parameters match.
       // now we just check the generic parameters match.
       if (CheckRedeclParamsMatch(
       if (CheckRedeclParamsMatch(
               context,
               context,
-              DeclParams(interface_decl_id, name.implicit_params_id,
+              DeclParams(interface_decl_id, name.first_param_node_id,
+                         name.last_param_node_id, name.implicit_params_id,
                          name.params_id),
                          name.params_id),
               DeclParams(context.interfaces().Get(
               DeclParams(context.interfaces().Get(
                   existing_interface_decl->interface_id)))) {
                   existing_interface_decl->interface_id)))) {
@@ -90,6 +91,8 @@ static auto BuildInterfaceDecl(Context& context,
         .name_id = name_context.name_id_for_new_inst(),
         .name_id = name_context.name_id_for_new_inst(),
         .parent_scope_id = name_context.parent_scope_id_for_new_inst(),
         .parent_scope_id = name_context.parent_scope_id_for_new_inst(),
         .generic_id = generic_id,
         .generic_id = generic_id,
+        .first_param_node_id = name.first_param_node_id,
+        .last_param_node_id = name.last_param_node_id,
         .implicit_param_refs_id = name.implicit_params_id,
         .implicit_param_refs_id = name.implicit_params_id,
         .param_refs_id = name.params_id,
         .param_refs_id = name.params_id,
         .decl_id = interface_decl_id};
         .decl_id = interface_decl_id};

+ 4 - 4
toolchain/check/handle_pattern_list.cpp

@@ -16,10 +16,10 @@ auto HandleParseNode(Context& context, Parse::ImplicitParamListStartId node_id)
 
 
 auto HandleParseNode(Context& context, Parse::ImplicitParamListId node_id)
 auto HandleParseNode(Context& context, Parse::ImplicitParamListId node_id)
     -> bool {
     -> bool {
+  // Note the Start node remains on the stack, where the param list handler can
+  // make use of it.
   auto refs_id = context.param_and_arg_refs_stack().EndAndPop(
   auto refs_id = context.param_and_arg_refs_stack().EndAndPop(
       Parse::NodeKind::ImplicitParamListStart);
       Parse::NodeKind::ImplicitParamListStart);
-  context.node_stack()
-      .PopAndDiscardSoloNodeId<Parse::NodeKind::ImplicitParamListStart>();
   context.node_stack().Push(node_id, refs_id);
   context.node_stack().Push(node_id, refs_id);
   // The implicit parameter list's scope extends to the end of the following
   // The implicit parameter list's scope extends to the end of the following
   // parameter list.
   // parameter list.
@@ -40,10 +40,10 @@ auto HandleParseNode(Context& context, Parse::PatternListCommaId /*node_id*/)
 }
 }
 
 
 auto HandleParseNode(Context& context, Parse::TuplePatternId node_id) -> bool {
 auto HandleParseNode(Context& context, Parse::TuplePatternId node_id) -> bool {
+  // Note the Start node remains on the stack, where the param list handler can
+  // make use of it.
   auto refs_id = context.param_and_arg_refs_stack().EndAndPop(
   auto refs_id = context.param_and_arg_refs_stack().EndAndPop(
       Parse::NodeKind::TuplePatternStart);
       Parse::NodeKind::TuplePatternStart);
-  context.node_stack()
-      .PopAndDiscardSoloNodeId<Parse::NodeKind::TuplePatternStart>();
   context.node_stack().Push(node_id, refs_id);
   context.node_stack().Push(node_id, refs_id);
   return true;
   return true;
 }
 }

+ 2 - 1
toolchain/check/impl.cpp

@@ -54,7 +54,8 @@ static auto CheckAssociatedFunctionImplementation(
   // synthesize a suitable thunk.
   // synthesize a suitable thunk.
   if (!CheckFunctionTypeMatches(
   if (!CheckFunctionTypeMatches(
           context, context.functions().Get(impl_function_decl->function_id),
           context, context.functions().Get(impl_function_decl->function_id),
-          context.functions().Get(interface_function_id), substitutions)) {
+          context.functions().Get(interface_function_id), substitutions,
+          /*check_syntax=*/false)) {
     return SemIR::InstId::BuiltinError;
     return SemIR::InstId::BuiltinError;
   }
   }
   return impl_decl_id;
   return impl_decl_id;

+ 6 - 0
toolchain/check/import_ref.cpp

@@ -909,6 +909,8 @@ class ImportRefResolver {
         // importing the parameters.
         // importing the parameters.
         .parent_scope_id = SemIR::NameScopeId::Invalid,
         .parent_scope_id = SemIR::NameScopeId::Invalid,
         .generic_id = generic_id,
         .generic_id = generic_id,
+        .first_param_node_id = Parse::NodeId::Invalid,
+        .last_param_node_id = Parse::NodeId::Invalid,
         .implicit_param_refs_id = import_class.implicit_param_refs_id.is_valid()
         .implicit_param_refs_id = import_class.implicit_param_refs_id.is_valid()
                                       ? SemIR::InstBlockId::Empty
                                       ? SemIR::InstBlockId::Empty
                                       : SemIR::InstBlockId::Invalid,
                                       : SemIR::InstBlockId::Invalid,
@@ -1143,6 +1145,8 @@ class ImportRefResolver {
          .parent_scope_id = parent_scope_id,
          .parent_scope_id = parent_scope_id,
          .decl_id = function_decl_id,
          .decl_id = function_decl_id,
          .generic_id = generic_id,
          .generic_id = generic_id,
+         .first_param_node_id = Parse::NodeId::Invalid,
+         .last_param_node_id = Parse::NodeId::Invalid,
          .implicit_param_refs_id = GetLocalParamRefsId(
          .implicit_param_refs_id = GetLocalParamRefsId(
              function.implicit_param_refs_id, implicit_param_const_ids),
              function.implicit_param_refs_id, implicit_param_const_ids),
          .param_refs_id =
          .param_refs_id =
@@ -1249,6 +1253,8 @@ class ImportRefResolver {
         // importing the parameters.
         // importing the parameters.
         .parent_scope_id = SemIR::NameScopeId::Invalid,
         .parent_scope_id = SemIR::NameScopeId::Invalid,
         .generic_id = generic_id,
         .generic_id = generic_id,
+        .first_param_node_id = Parse::NodeId::Invalid,
+        .last_param_node_id = Parse::NodeId::Invalid,
         .implicit_param_refs_id =
         .implicit_param_refs_id =
             import_interface.implicit_param_refs_id.is_valid()
             import_interface.implicit_param_refs_id.is_valid()
                 ? SemIR::InstBlockId::Empty
                 ? SemIR::InstBlockId::Empty

+ 82 - 3
toolchain/check/merge.cpp

@@ -268,9 +268,79 @@ static auto CheckRedeclParams(Context& context, SemIRLoc new_decl_loc,
   return true;
   return true;
 }
 }
 
 
+// Returns true if the two nodes represent the same syntax.
+// TODO: Detect raw identifiers (will require token changes).
+static auto IsNodeSyntaxEqual(Context& context, Parse::NodeId new_node_id,
+                              Parse::NodeId prev_node_id) -> bool {
+  if (context.parse_tree().node_kind(new_node_id) !=
+      context.parse_tree().node_kind(prev_node_id)) {
+    return false;
+  }
+
+  // TODO: Should there be a trivial way to check if we need to check spellings?
+  // Identifiers and literals need their text checked for cross-file matching,
+  // but not intra-file. Keywords and operators shouldn't need the token text
+  // examined at all.
+  auto new_spelling = context.tokens().GetTokenText(
+      context.parse_tree().node_token(new_node_id));
+  auto prev_spelling = context.tokens().GetTokenText(
+      context.parse_tree().node_token(prev_node_id));
+  return new_spelling == prev_spelling;
+}
+
+// Returns false if redeclaration parameter syntax doesn't match.
+static auto CheckRedeclParamSyntax(Context& context,
+                                   Parse::NodeId new_first_param_node_id,
+                                   Parse::NodeId new_last_param_node_id,
+                                   Parse::NodeId prev_first_param_node_id,
+                                   Parse::NodeId prev_last_param_node_id)
+    -> bool {
+  // Parse nodes may not always be available to compare.
+  // TODO: Support cross-file syntax checks. Right now imports provide invalid
+  // nodes, and we'll need to follow the declaration to its original file to
+  // get the parse tree.
+  if (!new_first_param_node_id.is_valid() ||
+      !prev_first_param_node_id.is_valid()) {
+    return true;
+  }
+  CARBON_CHECK(new_last_param_node_id.is_valid())
+      << "new_last_param_node_id.is_valid should match "
+         "new_first_param_node_id.is_valid";
+  CARBON_CHECK(prev_last_param_node_id.is_valid())
+      << "prev_last_param_node_id.is_valid should match "
+         "prev_first_param_node_id.is_valid";
+
+  auto new_range = context.parse_tree().postorder(new_first_param_node_id,
+                                                  new_last_param_node_id);
+  auto prev_range = context.parse_tree().postorder(prev_first_param_node_id,
+                                                   prev_last_param_node_id);
+
+  // zip is using the shortest range. If they differ in length, there should be
+  // some difference inside the range because the range includes parameter
+  // brackets. As a consequence, we don't explicitly handle different range
+  // sizes here.
+  for (auto [new_node_id, prev_node_id] : llvm::zip(new_range, prev_range)) {
+    if (!IsNodeSyntaxEqual(context, new_node_id, prev_node_id)) {
+      CARBON_DIAGNOSTIC(RedeclParamSyntaxDiffers, Error,
+                        "Redeclaration syntax differs here.");
+      CARBON_DIAGNOSTIC(RedeclParamSyntaxPrevious, Note,
+                        "Comparing with previous declaration here.");
+      context.emitter()
+          .Build(new_node_id, RedeclParamSyntaxDiffers)
+          .Note(prev_node_id, RedeclParamSyntaxPrevious)
+          .Emit();
+
+      return false;
+    }
+  }
+
+  return true;
+}
+
 auto CheckRedeclParamsMatch(Context& context, const DeclParams& new_entity,
 auto CheckRedeclParamsMatch(Context& context, const DeclParams& new_entity,
                             const DeclParams& prev_entity,
                             const DeclParams& prev_entity,
-                            Substitutions substitutions) -> bool {
+                            Substitutions substitutions, bool check_syntax)
+    -> bool {
   if (EntityHasParamError(context, new_entity) ||
   if (EntityHasParamError(context, new_entity) ||
       EntityHasParamError(context, prev_entity)) {
       EntityHasParamError(context, prev_entity)) {
     return false;
     return false;
@@ -278,12 +348,21 @@ auto CheckRedeclParamsMatch(Context& context, const DeclParams& new_entity,
   if (!CheckRedeclParams(context, new_entity.loc,
   if (!CheckRedeclParams(context, new_entity.loc,
                          new_entity.implicit_param_refs_id, prev_entity.loc,
                          new_entity.implicit_param_refs_id, prev_entity.loc,
                          prev_entity.implicit_param_refs_id, "implicit ",
                          prev_entity.implicit_param_refs_id, "implicit ",
-                         substitutions) ||
-      !CheckRedeclParams(context, new_entity.loc, new_entity.param_refs_id,
+                         substitutions)) {
+    return false;
+  }
+  if (!CheckRedeclParams(context, new_entity.loc, new_entity.param_refs_id,
                          prev_entity.loc, prev_entity.param_refs_id, "",
                          prev_entity.loc, prev_entity.param_refs_id, "",
                          substitutions)) {
                          substitutions)) {
     return false;
     return false;
   }
   }
+  if (check_syntax &&
+      !CheckRedeclParamSyntax(context, new_entity.first_param_node_id,
+                              new_entity.last_param_node_id,
+                              prev_entity.first_param_node_id,
+                              prev_entity.last_param_node_id)) {
+    return false;
+  }
   return true;
   return true;
 }
 }
 
 

+ 16 - 3
toolchain/check/merge.h

@@ -47,17 +47,30 @@ struct DeclParams {
   template <typename Entity>
   template <typename Entity>
   explicit DeclParams(const Entity& entity)
   explicit DeclParams(const Entity& entity)
       : loc(entity.decl_id),
       : loc(entity.decl_id),
+        first_param_node_id(entity.first_param_node_id),
+        last_param_node_id(entity.last_param_node_id),
         implicit_param_refs_id(entity.implicit_param_refs_id),
         implicit_param_refs_id(entity.implicit_param_refs_id),
         param_refs_id(entity.param_refs_id) {}
         param_refs_id(entity.param_refs_id) {}
 
 
-  DeclParams(SemIRLoc loc, SemIR::InstBlockId implicit_params_id,
+  DeclParams(SemIRLoc loc, Parse::NodeId first_param_node_id,
+             Parse::NodeId last_param_node_id,
+             SemIR::InstBlockId implicit_params_id,
              SemIR::InstBlockId params_id)
              SemIR::InstBlockId params_id)
       : loc(loc),
       : loc(loc),
+        first_param_node_id(first_param_node_id),
+        last_param_node_id(last_param_node_id),
         implicit_param_refs_id(implicit_params_id),
         implicit_param_refs_id(implicit_params_id),
         param_refs_id(params_id) {}
         param_refs_id(params_id) {}
 
 
   // The location of the declaration of the entity.
   // The location of the declaration of the entity.
   SemIRLoc loc;
   SemIRLoc loc;
+
+  // Parse tree bounds for the parameters, including both implicit and explicit
+  // parameters. These will be compared to match between declaration and
+  // definition.
+  Parse::NodeId first_param_node_id;
+  Parse::NodeId last_param_node_id;
+
   // The implicit parameters of the entity. Can be Invalid if there is no
   // The implicit parameters of the entity. Can be Invalid if there is no
   // implicit parameter list.
   // implicit parameter list.
   SemIR::InstBlockId implicit_param_refs_id;
   SemIR::InstBlockId implicit_param_refs_id;
@@ -71,8 +84,8 @@ struct DeclParams {
 // returns false.
 // returns false.
 auto CheckRedeclParamsMatch(Context& context, const DeclParams& new_entity,
 auto CheckRedeclParamsMatch(Context& context, const DeclParams& new_entity,
                             const DeclParams& prev_entity,
                             const DeclParams& prev_entity,
-                            Substitutions substitutions = Substitutions())
-    -> bool;
+                            Substitutions substitutions = Substitutions(),
+                            bool check_syntax = true) -> bool;
 
 
 }  // namespace Carbon::Check
 }  // namespace Carbon::Check
 
 

+ 25 - 0
toolchain/check/name_component.cpp

@@ -9,15 +9,40 @@
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
 auto PopNameComponent(Context& context) -> NameComponent {
 auto PopNameComponent(Context& context) -> NameComponent {
+  Parse::NodeId first_param_node_id = Parse::InvalidNodeId();
+  Parse::NodeId last_param_node_id = Parse::InvalidNodeId();
+
+  // Explicit params.
   auto [params_loc_id, params_id] =
   auto [params_loc_id, params_id] =
       context.node_stack().PopWithNodeIdIf<Parse::NodeKind::TuplePattern>();
       context.node_stack().PopWithNodeIdIf<Parse::NodeKind::TuplePattern>();
+  if (params_id) {
+    first_param_node_id =
+        context.node_stack()
+            .PopForSoloNodeId<Parse::NodeKind::TuplePatternStart>();
+    last_param_node_id = params_loc_id;
+  }
+
+  // Implicit params.
   auto [implicit_params_loc_id, implicit_params_id] =
   auto [implicit_params_loc_id, implicit_params_id] =
       context.node_stack()
       context.node_stack()
           .PopWithNodeIdIf<Parse::NodeKind::ImplicitParamList>();
           .PopWithNodeIdIf<Parse::NodeKind::ImplicitParamList>();
+  if (implicit_params_id) {
+    // Implicit params always come before explicit params.
+    first_param_node_id =
+        context.node_stack()
+            .PopForSoloNodeId<Parse::NodeKind::ImplicitParamListStart>();
+    // Only use the end of implicit params if there weren't explicit params.
+    if (last_param_node_id.is_valid()) {
+      last_param_node_id = params_loc_id;
+    }
+  }
+
   auto [name_loc_id, name_id] = context.node_stack().PopNameWithNodeId();
   auto [name_loc_id, name_id] = context.node_stack().PopNameWithNodeId();
   return {
   return {
       .name_loc_id = name_loc_id,
       .name_loc_id = name_loc_id,
       .name_id = name_id,
       .name_id = name_id,
+      .first_param_node_id = first_param_node_id,
+      .last_param_node_id = last_param_node_id,
       .implicit_params_loc_id = implicit_params_loc_id,
       .implicit_params_loc_id = implicit_params_loc_id,
       .implicit_params_id =
       .implicit_params_id =
           implicit_params_id.value_or(SemIR::InstBlockId::Invalid),
           implicit_params_id.value_or(SemIR::InstBlockId::Invalid),

+ 6 - 0
toolchain/check/name_component.h

@@ -20,6 +20,12 @@ struct NameComponent {
   Parse::NodeId name_loc_id;
   Parse::NodeId name_loc_id;
   SemIR::NameId name_id;
   SemIR::NameId name_id;
 
 
+  // Parse tree bounds for the parameters, including both implicit and explicit
+  // parameters. These will be compared to match between declaration and
+  // definition.
+  Parse::NodeId first_param_node_id;
+  Parse::NodeId last_param_node_id;
+
   // The implicit parameter list.
   // The implicit parameter list.
   Parse::NodeId implicit_params_loc_id;
   Parse::NodeId implicit_params_loc_id;
   SemIR::InstBlockId implicit_params_id;
   SemIR::InstBlockId implicit_params_id;

+ 2 - 2
toolchain/check/testdata/class/base_method.carbon

@@ -14,7 +14,7 @@ base class Base {
   fn F[addr self: Self*]();
   fn F[addr self: Self*]();
 }
 }
 
 
-fn Base.F[addr self: Base*]() {
+fn Base.F[addr self: Self*]() {
   (*self).a = 1;
   (*self).a = 1;
 }
 }
 
 
@@ -73,7 +73,7 @@ fn Call(p: Derived*) {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Base.decl: type = class_decl @Base [template = constants.%Base] {}
 // CHECK:STDOUT:   %Base.decl: type = class_decl @Base [template = constants.%Base] {}
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
-// CHECK:STDOUT:     %Base.ref: type = name_ref Base, %Base.decl [template = constants.%Base]
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%Base [template = constants.%Base]
 // CHECK:STDOUT:     %.loc17_26: type = ptr_type %Base [template = constants.%.3]
 // CHECK:STDOUT:     %.loc17_26: type = ptr_type %Base [template = constants.%.3]
 // CHECK:STDOUT:     %self.loc17_16.1: %.3 = param self
 // CHECK:STDOUT:     %self.loc17_16.1: %.3 = param self
 // CHECK:STDOUT:     @F.%self: %.3 = bind_name self, %self.loc17_16.1
 // CHECK:STDOUT:     @F.%self: %.3 = bind_name self, %self.loc17_16.1

+ 794 - 0
toolchain/check/testdata/class/no_prelude/syntactic_merge.carbon

@@ -0,0 +1,794 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// AUTOUPDATE
+// TIP: To test this file alone, run:
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/class/no_prelude/syntactic_merge.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/no_prelude/syntactic_merge.carbon
+
+// --- basic.carbon
+
+library "basic";
+
+class C {}
+alias D = C;
+
+class Foo(a: C);
+class Foo(a: C) {}
+
+class Bar(a: D);
+class Bar(a: D) {}
+
+// --- spacing.carbon
+
+library "spacing";
+
+class C {}
+
+class Foo [ ] ( a : C );
+class Foo[](a: C) {}
+
+// --- fail_parens.carbon
+
+library "parens";
+
+class C {}
+
+class Foo(a: C);
+// CHECK:STDERR: fail_parens.carbon:[[@LINE+7]]:14: ERROR: Redeclaration syntax differs here.
+// CHECK:STDERR: class Foo(a: (C)) {}
+// CHECK:STDERR:              ^
+// CHECK:STDERR: fail_parens.carbon:[[@LINE-4]]:14: Comparing with previous declaration here.
+// CHECK:STDERR: class Foo(a: C);
+// CHECK:STDERR:              ^
+// CHECK:STDERR:
+class Foo(a: (C)) {}
+
+// --- todo_fail_raw_identifier.carbon
+
+library "raw_identifier";
+
+class C {}
+
+class Foo(a: C);
+class Foo(a: r#C) {}
+
+// --- two_file.carbon
+
+library "two_file";
+
+class C {}
+alias D = C;
+
+class Foo(a: C);
+class Bar(a: D);
+
+// --- two_file.impl.carbon
+
+impl library "two_file";
+
+class Foo(a: C) {}
+class Bar(a: D) {}
+
+// --- fail_name_mismatch.carbon
+
+library "name_mismatch";
+
+class C {}
+alias D = C;
+
+class Foo(a: C);
+// CHECK:STDERR: fail_name_mismatch.carbon:[[@LINE+7]]:11: ERROR: Redeclaration differs at parameter 1.
+// CHECK:STDERR: class Foo(b: D) {}
+// CHECK:STDERR:           ^
+// CHECK:STDERR: fail_name_mismatch.carbon:[[@LINE-4]]:11: Previous declaration's corresponding parameter here.
+// CHECK:STDERR: class Foo(a: C);
+// CHECK:STDERR:           ^
+// CHECK:STDERR:
+class Foo(b: D) {}
+
+// --- fail_alias.carbon
+
+library "alias";
+
+class C {}
+alias D = C;
+
+class Foo(a: C);
+// CHECK:STDERR: fail_alias.carbon:[[@LINE+7]]:14: ERROR: Redeclaration syntax differs here.
+// CHECK:STDERR: class Foo(a: D) {}
+// CHECK:STDERR:              ^
+// CHECK:STDERR: fail_alias.carbon:[[@LINE-4]]:14: Comparing with previous declaration here.
+// CHECK:STDERR: class Foo(a: C);
+// CHECK:STDERR:              ^
+// CHECK:STDERR:
+class Foo(a: D) {}
+
+// --- fail_deduced_alias.carbon
+
+library "deduced_alias";
+
+class C {}
+alias D = C;
+
+class Foo[a: C]();
+// CHECK:STDERR: fail_deduced_alias.carbon:[[@LINE+7]]:14: ERROR: Redeclaration syntax differs here.
+// CHECK:STDERR: class Foo[a: D]() {}
+// CHECK:STDERR:              ^
+// CHECK:STDERR: fail_deduced_alias.carbon:[[@LINE-4]]:14: Comparing with previous declaration here.
+// CHECK:STDERR: class Foo[a: C]();
+// CHECK:STDERR:              ^
+// CHECK:STDERR:
+class Foo[a: D]() {}
+
+// --- alias_two_file.carbon
+
+library "alias_two_file";
+
+class C {}
+
+class Foo(a: C);
+
+// --- todo_fail_alias_two_file.impl.carbon
+
+impl library "alias_two_file";
+
+alias D = C;
+
+class Foo(a: D) {}
+
+// --- fail_repeat_const.carbon
+
+library "repeat_const";
+
+class C {}
+
+class Foo(a: const C);
+// CHECK:STDERR: fail_repeat_const.carbon:[[@LINE+11]]:14: WARNING: `const` applied repeatedly to the same type has no additional effect.
+// CHECK:STDERR: class Foo(a: const (const C)) {}
+// CHECK:STDERR:              ^~~~~~~~~~~~~~~
+// CHECK:STDERR:
+// CHECK:STDERR: fail_repeat_const.carbon:[[@LINE+7]]:20: ERROR: Redeclaration syntax differs here.
+// CHECK:STDERR: class Foo(a: const (const C)) {}
+// CHECK:STDERR:                    ^
+// CHECK:STDERR: fail_repeat_const.carbon:[[@LINE-8]]:20: Comparing with previous declaration here.
+// CHECK:STDERR: class Foo(a: const C);
+// CHECK:STDERR:                    ^
+// CHECK:STDERR:
+class Foo(a: const (const C)) {}
+
+// --- fail_self_type.carbon
+
+library "self_type";
+
+base class Base {
+  var a: ();
+
+  fn F[addr self: Self*]();
+}
+
+// CHECK:STDERR: fail_self_type.carbon:[[@LINE+6]]:22: ERROR: Redeclaration syntax differs here.
+// CHECK:STDERR: fn Base.F[addr self: Base*]() {
+// CHECK:STDERR:                      ^~~~
+// CHECK:STDERR: fail_self_type.carbon:[[@LINE-6]]:19: Comparing with previous declaration here.
+// CHECK:STDERR:   fn F[addr self: Self*]();
+// CHECK:STDERR:                   ^~~~
+fn Base.F[addr self: Base*]() {
+  (*self).a = ();
+}
+
+// CHECK:STDOUT: --- basic.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = generic_class_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo.1: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %Foo.2: type = class_type @Foo [template]
+// CHECK:STDOUT:   %Bar.type: type = generic_class_type @Bar [template]
+// CHECK:STDOUT:   %Bar.1: %Bar.type = struct_value () [template]
+// CHECK:STDOUT:   %Bar.2: type = class_type @Bar [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .D = %D
+// CHECK:STDOUT:     .Foo = %Foo.decl.loc7
+// CHECK:STDOUT:     .Bar = %Bar.decl.loc10
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %C.ref.loc5: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %D: type = bind_alias D, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %Foo.decl.loc7: %Foo.type = class_decl @Foo [template = constants.%Foo.1] {
+// CHECK:STDOUT:     %C.ref.loc7: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc7_11.1: %C = param a
+// CHECK:STDOUT:     %a.loc7_11.2: %C = bind_name a, %a.loc7_11.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Foo.decl.loc8: %Foo.type = class_decl @Foo [template = constants.%Foo.1] {
+// CHECK:STDOUT:     %C.ref.loc8: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc8_11.1: %C = param a
+// CHECK:STDOUT:     %a.loc8_11.2: %C = bind_name a, %a.loc8_11.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Bar.decl.loc10: %Bar.type = class_decl @Bar [template = constants.%Bar.1] {
+// CHECK:STDOUT:     %D.ref.loc10: type = name_ref D, %D [template = constants.%C]
+// CHECK:STDOUT:     %a.loc10_11.1: %C = param a
+// CHECK:STDOUT:     %a.loc10_11.2: %C = bind_name a, %a.loc10_11.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Bar.decl.loc11: %Bar.type = class_decl @Bar [template = constants.%Bar.1] {
+// CHECK:STDOUT:     %D.ref.loc11: type = name_ref D, %D [template = constants.%C]
+// CHECK:STDOUT:     %a.loc11_11.1: %C = param a
+// CHECK:STDOUT:     %a.loc11_11.2: %C = bind_name a, %a.loc11_11.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @Foo {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%Foo.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @Bar {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%Bar.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- spacing.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = generic_class_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo.1: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %Foo.2: type = class_type @Foo [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .Foo = %Foo.decl.loc6
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %Foo.decl.loc6: %Foo.type = class_decl @Foo [template = constants.%Foo.1] {
+// CHECK:STDOUT:     %C.ref.loc6: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc6_17.1: %C = param a
+// CHECK:STDOUT:     %a.loc6_17.2: %C = bind_name a, %a.loc6_17.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Foo.decl.loc7: %Foo.type = class_decl @Foo [template = constants.%Foo.1] {
+// CHECK:STDOUT:     %C.ref.loc7: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc7_13.1: %C = param a
+// CHECK:STDOUT:     %a.loc7_13.2: %C = bind_name a, %a.loc7_13.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @Foo {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%Foo.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_parens.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = generic_class_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo.1: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %Foo.2: type = class_type @Foo [template]
+// CHECK:STDOUT:   %.type: type = generic_class_type @.1 [template]
+// CHECK:STDOUT:   %.3: %.type = struct_value () [template]
+// CHECK:STDOUT:   %.4: type = class_type @.1 [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = class_decl @Foo [template = constants.%Foo.1] {
+// CHECK:STDOUT:     %C.ref.loc6: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc6_11.1: %C = param a
+// CHECK:STDOUT:     %a.loc6_11.2: %C = bind_name a, %a.loc6_11.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.decl: %.type = class_decl @.1 [template = constants.%.3] {
+// CHECK:STDOUT:     %C.ref.loc14: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc14_11.1: %C = param a
+// CHECK:STDOUT:     %a.loc14_11.2: %C = bind_name a, %a.loc14_11.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @Foo;
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @.1 {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%.4
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- todo_fail_raw_identifier.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = generic_class_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo.1: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %Foo.2: type = class_type @Foo [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .Foo = %Foo.decl.loc6
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %Foo.decl.loc6: %Foo.type = class_decl @Foo [template = constants.%Foo.1] {
+// CHECK:STDOUT:     %C.ref.loc6: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc6_11.1: %C = param a
+// CHECK:STDOUT:     %a.loc6_11.2: %C = bind_name a, %a.loc6_11.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Foo.decl.loc7: %Foo.type = class_decl @Foo [template = constants.%Foo.1] {
+// CHECK:STDOUT:     %C.ref.loc7: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc7_11.1: %C = param a
+// CHECK:STDOUT:     %a.loc7_11.2: %C = bind_name a, %a.loc7_11.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @Foo {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%Foo.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- two_file.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = generic_class_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo.1: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %Foo.2: type = class_type @Foo [template]
+// CHECK:STDOUT:   %Bar.type: type = generic_class_type @Bar [template]
+// CHECK:STDOUT:   %Bar.1: %Bar.type = struct_value () [template]
+// CHECK:STDOUT:   %Bar.2: type = class_type @Bar [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .D = %D
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:     .Bar = %Bar.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %C.ref.loc5: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %D: type = bind_alias D, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = class_decl @Foo [template = constants.%Foo.1] {
+// CHECK:STDOUT:     %C.ref.loc7: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc7_11.1: %C = param a
+// CHECK:STDOUT:     %a.loc7_11.2: %C = bind_name a, %a.loc7_11.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Bar.decl: %Bar.type = class_decl @Bar [template = constants.%Bar.1] {
+// CHECK:STDOUT:     %D.ref: type = name_ref D, %D [template = constants.%C]
+// CHECK:STDOUT:     %a.loc8_11.1: %C = param a
+// CHECK:STDOUT:     %a.loc8_11.2: %C = bind_name a, %a.loc8_11.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @Foo;
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @Bar;
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- two_file.impl.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = generic_class_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo.1: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %Foo.2: type = class_type @Foo [template]
+// CHECK:STDOUT:   %Bar.type: type = generic_class_type @Bar [template]
+// CHECK:STDOUT:   %Bar.1: %Bar.type = struct_value () [template]
+// CHECK:STDOUT:   %Bar.2: type = class_type @Bar [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//two_file, inst+1, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.2: type = import_ref Main//two_file, inst+5, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.3: %Foo.type = import_ref Main//two_file, inst+9, loaded [template = constants.%Foo.1]
+// CHECK:STDOUT:   %import_ref.4: %Bar.type = import_ref Main//two_file, inst+17, loaded [template = constants.%Bar.1]
+// CHECK:STDOUT:   %import_ref.5 = import_ref Main//two_file, inst+2, unloaded
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = imports.%import_ref.1
+// CHECK:STDOUT:     .D = imports.%import_ref.2
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:     .Bar = %Bar.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %default.import.loc2_6.1 = import <invalid>
+// CHECK:STDOUT:   %default.import.loc2_6.2 = import <invalid>
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = class_decl @Foo [template = constants.%Foo.1] {
+// CHECK:STDOUT:     %C.ref: type = name_ref C, imports.%import_ref.1 [template = constants.%C]
+// CHECK:STDOUT:     %a.loc4_11.1: %C = param a
+// CHECK:STDOUT:     %a.loc4_11.2: %C = bind_name a, %a.loc4_11.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Bar.decl: %Bar.type = class_decl @Bar [template = constants.%Bar.1] {
+// CHECK:STDOUT:     %D.ref: type = name_ref D, imports.%import_ref.2 [template = constants.%C]
+// CHECK:STDOUT:     %a.loc5_11.1: %C = param a
+// CHECK:STDOUT:     %a.loc5_11.2: %C = bind_name a, %a.loc5_11.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = imports.%import_ref.5
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @Foo {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%Foo.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @Bar {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%Bar.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_name_mismatch.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = generic_class_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo.1: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %Foo.2: type = class_type @Foo [template]
+// CHECK:STDOUT:   %.type: type = generic_class_type @.1 [template]
+// CHECK:STDOUT:   %.3: %.type = struct_value () [template]
+// CHECK:STDOUT:   %.4: type = class_type @.1 [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .D = %D
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %C.ref.loc5: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %D: type = bind_alias D, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = class_decl @Foo [template = constants.%Foo.1] {
+// CHECK:STDOUT:     %C.ref.loc7: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc7_11.1: %C = param a
+// CHECK:STDOUT:     %a.loc7_11.2: %C = bind_name a, %a.loc7_11.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.decl: %.type = class_decl @.1 [template = constants.%.3] {
+// CHECK:STDOUT:     %D.ref: type = name_ref D, %D [template = constants.%C]
+// CHECK:STDOUT:     %b.loc15_11.1: %C = param b
+// CHECK:STDOUT:     %b.loc15_11.2: %C = bind_name b, %b.loc15_11.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @Foo;
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @.1 {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%.4
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_alias.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = generic_class_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo.1: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %Foo.2: type = class_type @Foo [template]
+// CHECK:STDOUT:   %.type: type = generic_class_type @.1 [template]
+// CHECK:STDOUT:   %.3: %.type = struct_value () [template]
+// CHECK:STDOUT:   %.4: type = class_type @.1 [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .D = %D
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %C.ref.loc5: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %D: type = bind_alias D, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = class_decl @Foo [template = constants.%Foo.1] {
+// CHECK:STDOUT:     %C.ref.loc7: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc7_11.1: %C = param a
+// CHECK:STDOUT:     %a.loc7_11.2: %C = bind_name a, %a.loc7_11.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.decl: %.type = class_decl @.1 [template = constants.%.3] {
+// CHECK:STDOUT:     %D.ref: type = name_ref D, %D [template = constants.%C]
+// CHECK:STDOUT:     %a.loc15_11.1: %C = param a
+// CHECK:STDOUT:     %a.loc15_11.2: %C = bind_name a, %a.loc15_11.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @Foo;
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @.1 {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%.4
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_deduced_alias.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = generic_class_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo.1: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %Foo.2: type = class_type @Foo [template]
+// CHECK:STDOUT:   %.type: type = generic_class_type @.1 [template]
+// CHECK:STDOUT:   %.3: %.type = struct_value () [template]
+// CHECK:STDOUT:   %.4: type = class_type @.1 [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .D = %D
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %C.ref.loc5: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %D: type = bind_alias D, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = class_decl @Foo [template = constants.%Foo.1] {
+// CHECK:STDOUT:     %C.ref.loc7: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc7_11.1: %C = param a
+// CHECK:STDOUT:     %a.loc7_11.2: %C = bind_name a, %a.loc7_11.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.decl: %.type = class_decl @.1 [template = constants.%.3] {
+// CHECK:STDOUT:     %D.ref: type = name_ref D, %D [template = constants.%C]
+// CHECK:STDOUT:     %a.loc15_11.1: %C = param a
+// CHECK:STDOUT:     %a.loc15_11.2: %C = bind_name a, %a.loc15_11.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @Foo;
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @.1 {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%.4
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- alias_two_file.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = generic_class_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo.1: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %Foo.2: type = class_type @Foo [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = class_decl @Foo [template = constants.%Foo.1] {
+// CHECK:STDOUT:     %C.ref: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc6_11.1: %C = param a
+// CHECK:STDOUT:     %a.loc6_11.2: %C = bind_name a, %a.loc6_11.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @Foo;
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- todo_fail_alias_two_file.impl.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = generic_class_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo.1: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %Foo.2: type = class_type @Foo [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//alias_two_file, inst+1, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.2: %Foo.type = import_ref Main//alias_two_file, inst+7, loaded [template = constants.%Foo.1]
+// CHECK:STDOUT:   %import_ref.3 = import_ref Main//alias_two_file, inst+2, unloaded
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = imports.%import_ref.1
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:     .D = %D
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %default.import.loc2_6.1 = import <invalid>
+// CHECK:STDOUT:   %default.import.loc2_6.2 = import <invalid>
+// CHECK:STDOUT:   %C.ref: type = name_ref C, imports.%import_ref.1 [template = constants.%C]
+// CHECK:STDOUT:   %D: type = bind_alias D, imports.%import_ref.1 [template = constants.%C]
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = class_decl @Foo [template = constants.%Foo.1] {
+// CHECK:STDOUT:     %D.ref: type = name_ref D, %D [template = constants.%C]
+// CHECK:STDOUT:     %a.loc6_11.1: %C = param a
+// CHECK:STDOUT:     %a.loc6_11.2: %C = bind_name a, %a.loc6_11.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = imports.%import_ref.3
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @Foo {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%Foo.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_repeat_const.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %.2: type = const_type %C [template]
+// CHECK:STDOUT:   %Foo.type: type = generic_class_type @Foo [template]
+// CHECK:STDOUT:   %.3: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo.1: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %Foo.2: type = class_type @Foo [template]
+// CHECK:STDOUT:   %.type: type = generic_class_type @.1 [template]
+// CHECK:STDOUT:   %.4: %.type = struct_value () [template]
+// CHECK:STDOUT:   %.5: type = class_type @.1 [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = class_decl @Foo [template = constants.%Foo.1] {
+// CHECK:STDOUT:     %C.ref.loc6: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %.loc6: type = const_type %C [template = constants.%.2]
+// CHECK:STDOUT:     %a.loc6_11.1: %.2 = param a
+// CHECK:STDOUT:     %a.loc6_11.2: %.2 = bind_name a, %a.loc6_11.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.decl: %.type = class_decl @.1 [template = constants.%.4] {
+// CHECK:STDOUT:     %C.ref.loc18: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %.loc18_21: type = const_type %C [template = constants.%.2]
+// CHECK:STDOUT:     %.loc18_14: type = const_type %.2 [template = constants.%.2]
+// CHECK:STDOUT:     %a.loc18_11.1: %.2 = param a
+// CHECK:STDOUT:     %a.loc18_11.2: %.2 = bind_name a, %a.loc18_11.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @Foo;
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @.1 {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%.5
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_self_type.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %Base: type = class_type @Base [template]
+// CHECK:STDOUT:   %.1: type = tuple_type () [template]
+// CHECK:STDOUT:   %.2: type = unbound_element_type %Base, %.1 [template]
+// CHECK:STDOUT:   %.3: type = ptr_type %Base [template]
+// CHECK:STDOUT:   %F.type: type = fn_type @F [template]
+// CHECK:STDOUT:   %F: %F.type = struct_value () [template]
+// CHECK:STDOUT:   %.4: type = struct_type {.a: %.1} [template]
+// CHECK:STDOUT:   %.type: type = fn_type @.1 [template]
+// CHECK:STDOUT:   %.5: %.type = struct_value () [template]
+// CHECK:STDOUT:   %.6: type = ptr_type %.4 [template]
+// CHECK:STDOUT:   %tuple: %.1 = tuple_value () [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Base = %Base.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Base.decl: type = class_decl @Base [template = constants.%Base] {}
+// CHECK:STDOUT:   %.decl: %.type = fn_decl @.1 [template = constants.%.5] {
+// CHECK:STDOUT:     %Base.ref: type = name_ref Base, %Base.decl [template = constants.%Base]
+// CHECK:STDOUT:     %.loc16_26: type = ptr_type %Base [template = constants.%.3]
+// CHECK:STDOUT:     %self.loc16_16.1: %.3 = param self
+// CHECK:STDOUT:     @.1.%self: %.3 = bind_name self, %self.loc16_16.1
+// CHECK:STDOUT:     @.1.%.loc16: %.3 = addr_pattern @.1.%self
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @Base {
+// CHECK:STDOUT:   %.loc5_11.1: %.1 = tuple_literal ()
+// CHECK:STDOUT:   %.loc5_11.2: type = converted %.loc5_11.1, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:   %.loc5_8: %.2 = field_decl a, element0 [template]
+// CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%Base [template = constants.%Base]
+// CHECK:STDOUT:     %.loc7_23: type = ptr_type %Base [template = constants.%.3]
+// CHECK:STDOUT:     %self.loc7_13.1: %.3 = param self
+// CHECK:STDOUT:     %self.loc7_13.3: %.3 = bind_name self, %self.loc7_13.1
+// CHECK:STDOUT:     %.loc7_8: %.3 = addr_pattern %self.loc7_13.3
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%Base
+// CHECK:STDOUT:   .a = %.loc5_8
+// CHECK:STDOUT:   .F = %F.decl
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F[addr @Base.%self.loc7_13.3: %.3]();
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @.1[addr %self: %.3]() {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %self.ref: %.3 = name_ref self, %self
+// CHECK:STDOUT:   %.loc17_4: ref %Base = deref %self.ref
+// CHECK:STDOUT:   %a.ref: %.2 = name_ref a, @Base.%.loc5_8 [template = @Base.%.loc5_8]
+// CHECK:STDOUT:   %.loc17_10: ref %.1 = class_element_access %.loc17_4, element0
+// CHECK:STDOUT:   %.loc17_16.1: %.1 = tuple_literal ()
+// CHECK:STDOUT:   %.loc17_16.2: init %.1 = tuple_init () to %.loc17_10 [template = constants.%tuple]
+// CHECK:STDOUT:   %.loc17_13: init %.1 = converted %.loc17_16.1, %.loc17_16.2 [template = constants.%tuple]
+// CHECK:STDOUT:   assign %.loc17_10, %.loc17_13
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:

+ 191 - 0
toolchain/check/testdata/class/syntactic_merge_literal.carbon

@@ -0,0 +1,191 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// AUTOUPDATE
+// TIP: To test this file alone, run:
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/class/syntactic_merge_literal.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/syntactic_merge_literal.carbon
+// CHECK:STDERR: fail_int_mismatch.carbon: ERROR: Main//default previously provided by `int_match.carbon`.
+// CHECK:STDERR:
+
+// --- int_match.carbon
+
+class C(a: i32) {}
+class D(b: C(1_000));
+class D(b: C(1_000)) {}
+
+// --- fail_int_mismatch.carbon
+
+class C(a: i32) {}
+class D(b: C(1000));
+// CHECK:STDERR: fail_int_mismatch.carbon:[[@LINE+6]]:14: ERROR: Redeclaration syntax differs here.
+// CHECK:STDERR: class D(b: C(1_000)) {}
+// CHECK:STDERR:              ^~~~~
+// CHECK:STDERR: fail_int_mismatch.carbon:[[@LINE-4]]:14: Comparing with previous declaration here.
+// CHECK:STDERR: class D(b: C(1000));
+// CHECK:STDERR:              ^~~~
+class D(b: C(1_000)) {}
+
+// CHECK:STDOUT: --- int_match.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %Int32.type: type = fn_type @Int32 [template]
+// CHECK:STDOUT:   %.1: type = tuple_type () [template]
+// CHECK:STDOUT:   %Int32: %Int32.type = struct_value () [template]
+// CHECK:STDOUT:   %C.type: type = generic_class_type @C [template]
+// CHECK:STDOUT:   %C.1: %C.type = struct_value () [template]
+// CHECK:STDOUT:   %C.2: type = class_type @C [template]
+// CHECK:STDOUT:   %.2: type = struct_type {} [template]
+// CHECK:STDOUT:   %.3: i32 = int_literal 1000 [template]
+// CHECK:STDOUT:   %C.3: type = class_type @C, <invalid>(%.3) [template]
+// CHECK:STDOUT:   %D.type: type = generic_class_type @D [template]
+// CHECK:STDOUT:   %D.1: %D.type = struct_value () [template]
+// CHECK:STDOUT:   %D.2: type = class_type @D [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %import_ref: %Int32.type = import_ref Core//prelude/types, inst+4, loaded [template = constants.%Int32]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = %Core
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .D = %D.decl.loc3
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %Core: <namespace> = namespace %Core.import, [template] {
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/operators
+// CHECK:STDOUT:     import Core//prelude/types
+// CHECK:STDOUT:     import Core//prelude/operators/arithmetic
+// CHECK:STDOUT:     import Core//prelude/operators/bitwise
+// CHECK:STDOUT:     import Core//prelude/operators/comparison
+// CHECK:STDOUT:     import Core//prelude/types/bool
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: %C.type = class_decl @C [template = constants.%C.1] {
+// CHECK:STDOUT:     %int.make_type_32: init type = call constants.%Int32() [template = i32]
+// CHECK:STDOUT:     %.loc2_12.1: type = value_of_initializer %int.make_type_32 [template = i32]
+// CHECK:STDOUT:     %.loc2_12.2: type = converted %int.make_type_32, %.loc2_12.1 [template = i32]
+// CHECK:STDOUT:     %a.loc2_9.1: i32 = param a
+// CHECK:STDOUT:     %a.loc2_9.2: i32 = bind_name a, %a.loc2_9.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %D.decl.loc3: %D.type = class_decl @D [template = constants.%D.1] {
+// CHECK:STDOUT:     %C.ref.loc3: %C.type = name_ref C, %C.decl [template = constants.%C.1]
+// CHECK:STDOUT:     %.loc3_14: i32 = int_literal 1000 [template = constants.%.3]
+// CHECK:STDOUT:     %.loc3_13: init type = call %C.ref.loc3(%.loc3_14) [template = constants.%C.3]
+// CHECK:STDOUT:     %.loc3_19.1: type = value_of_initializer %.loc3_13 [template = constants.%C.3]
+// CHECK:STDOUT:     %.loc3_19.2: type = converted %.loc3_13, %.loc3_19.1 [template = constants.%C.3]
+// CHECK:STDOUT:     %b.loc3_9.1: %C.3 = param b
+// CHECK:STDOUT:     %b.loc3_9.2: %C.3 = bind_name b, %b.loc3_9.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %D.decl.loc4: %D.type = class_decl @D [template = constants.%D.1] {
+// CHECK:STDOUT:     %C.ref.loc4: %C.type = name_ref C, %C.decl [template = constants.%C.1]
+// CHECK:STDOUT:     %.loc4_14: i32 = int_literal 1000 [template = constants.%.3]
+// CHECK:STDOUT:     %.loc4_13: init type = call %C.ref.loc4(%.loc4_14) [template = constants.%C.3]
+// CHECK:STDOUT:     %.loc4_19.1: type = value_of_initializer %.loc4_13 [template = constants.%C.3]
+// CHECK:STDOUT:     %.loc4_19.2: type = converted %.loc4_13, %.loc4_19.1 [template = constants.%C.3]
+// CHECK:STDOUT:     %b.loc4_9.1: %C.3 = param b
+// CHECK:STDOUT:     %b.loc4_9.2: %C.3 = bind_name b, %b.loc4_9.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @D {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%D.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32";
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific <invalid>(constants.%.3);
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_int_mismatch.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %Int32.type: type = fn_type @Int32 [template]
+// CHECK:STDOUT:   %.1: type = tuple_type () [template]
+// CHECK:STDOUT:   %Int32: %Int32.type = struct_value () [template]
+// CHECK:STDOUT:   %C.type: type = generic_class_type @C [template]
+// CHECK:STDOUT:   %C.1: %C.type = struct_value () [template]
+// CHECK:STDOUT:   %C.2: type = class_type @C [template]
+// CHECK:STDOUT:   %.2: type = struct_type {} [template]
+// CHECK:STDOUT:   %.3: i32 = int_literal 1000 [template]
+// CHECK:STDOUT:   %C.3: type = class_type @C, <invalid>(%.3) [template]
+// CHECK:STDOUT:   %D.type: type = generic_class_type @D [template]
+// CHECK:STDOUT:   %D.1: %D.type = struct_value () [template]
+// CHECK:STDOUT:   %D.2: type = class_type @D [template]
+// CHECK:STDOUT:   %.type: type = generic_class_type @.1 [template]
+// CHECK:STDOUT:   %.4: %.type = struct_value () [template]
+// CHECK:STDOUT:   %.5: type = class_type @.1 [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %import_ref: %Int32.type = import_ref Core//prelude/types, inst+4, loaded [template = constants.%Int32]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = %Core
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .D = %D.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %Core: <namespace> = namespace %Core.import, [template] {
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/operators
+// CHECK:STDOUT:     import Core//prelude/types
+// CHECK:STDOUT:     import Core//prelude/operators/arithmetic
+// CHECK:STDOUT:     import Core//prelude/operators/bitwise
+// CHECK:STDOUT:     import Core//prelude/operators/comparison
+// CHECK:STDOUT:     import Core//prelude/types/bool
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: %C.type = class_decl @C [template = constants.%C.1] {
+// CHECK:STDOUT:     %int.make_type_32: init type = call constants.%Int32() [template = i32]
+// CHECK:STDOUT:     %.loc2_12.1: type = value_of_initializer %int.make_type_32 [template = i32]
+// CHECK:STDOUT:     %.loc2_12.2: type = converted %int.make_type_32, %.loc2_12.1 [template = i32]
+// CHECK:STDOUT:     %a.loc2_9.1: i32 = param a
+// CHECK:STDOUT:     %a.loc2_9.2: i32 = bind_name a, %a.loc2_9.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %D.decl: %D.type = class_decl @D [template = constants.%D.1] {
+// CHECK:STDOUT:     %C.ref.loc3: %C.type = name_ref C, %C.decl [template = constants.%C.1]
+// CHECK:STDOUT:     %.loc3_14: i32 = int_literal 1000 [template = constants.%.3]
+// CHECK:STDOUT:     %.loc3_13: init type = call %C.ref.loc3(%.loc3_14) [template = constants.%C.3]
+// CHECK:STDOUT:     %.loc3_18.1: type = value_of_initializer %.loc3_13 [template = constants.%C.3]
+// CHECK:STDOUT:     %.loc3_18.2: type = converted %.loc3_13, %.loc3_18.1 [template = constants.%C.3]
+// CHECK:STDOUT:     %b.loc3_9.1: %C.3 = param b
+// CHECK:STDOUT:     %b.loc3_9.2: %C.3 = bind_name b, %b.loc3_9.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.decl: %.type = class_decl @.1 [template = constants.%.4] {
+// CHECK:STDOUT:     %C.ref.loc10: %C.type = name_ref C, %C.decl [template = constants.%C.1]
+// CHECK:STDOUT:     %.loc10_14: i32 = int_literal 1000 [template = constants.%.3]
+// CHECK:STDOUT:     %.loc10_13: init type = call %C.ref.loc10(%.loc10_14) [template = constants.%C.3]
+// CHECK:STDOUT:     %.loc10_19.1: type = value_of_initializer %.loc10_13 [template = constants.%C.3]
+// CHECK:STDOUT:     %.loc10_19.2: type = converted %.loc10_13, %.loc10_19.1 [template = constants.%C.3]
+// CHECK:STDOUT:     %b.loc10_9.1: %C.3 = param b
+// CHECK:STDOUT:     %b.loc10_9.2: %C.3 = bind_name b, %b.loc10_9.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @D;
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @.1 {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%.5
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32";
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific <invalid>(constants.%.3);
+// CHECK:STDOUT:

+ 754 - 0
toolchain/check/testdata/function/definition/no_prelude/syntactic_merge.carbon

@@ -0,0 +1,754 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// AUTOUPDATE
+// TIP: To test this file alone, run:
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/function/definition/no_prelude/syntactic_merge.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/function/definition/no_prelude/syntactic_merge.carbon
+
+// --- basic.carbon
+
+library "basic";
+
+class C {}
+alias D = C;
+
+fn Foo(a: C);
+fn Foo(a: C) {}
+
+fn Bar(a: D);
+fn Bar(a: D) {}
+
+// --- spacing.carbon
+
+library "spacing";
+
+class C {}
+
+fn Foo [ ] ( a : C );
+fn Foo[](a: C) {}
+
+// --- fail_parens.carbon
+
+library "parens";
+
+class C {}
+
+fn Foo(a: C);
+// CHECK:STDERR: fail_parens.carbon:[[@LINE+7]]:11: ERROR: Redeclaration syntax differs here.
+// CHECK:STDERR: fn Foo(a: (C)) {}
+// CHECK:STDERR:           ^
+// CHECK:STDERR: fail_parens.carbon:[[@LINE-4]]:11: Comparing with previous declaration here.
+// CHECK:STDERR: fn Foo(a: C);
+// CHECK:STDERR:           ^
+// CHECK:STDERR:
+fn Foo(a: (C)) {}
+
+// --- todo_fail_raw_identifier.carbon
+
+library "raw_identifier";
+
+class C {}
+
+fn Foo(a: C);
+fn Foo(a: r#C) {}
+
+// --- two_file.carbon
+
+library "two_file";
+
+class C {}
+alias D = C;
+
+fn Foo(a: C);
+fn Bar(a: D);
+
+// --- two_file.impl.carbon
+
+impl library "two_file";
+
+fn Foo(a: C) {}
+fn Bar(a: D) {}
+
+// --- fail_name_mismatch.carbon
+
+library "name_mismatch";
+
+class C {}
+alias D = C;
+
+fn Foo(a: C);
+// CHECK:STDERR: fail_name_mismatch.carbon:[[@LINE+7]]:8: ERROR: Redeclaration differs at parameter 1.
+// CHECK:STDERR: fn Foo(b: D) {}
+// CHECK:STDERR:        ^
+// CHECK:STDERR: fail_name_mismatch.carbon:[[@LINE-4]]:8: Previous declaration's corresponding parameter here.
+// CHECK:STDERR: fn Foo(a: C);
+// CHECK:STDERR:        ^
+// CHECK:STDERR:
+fn Foo(b: D) {}
+
+// --- fail_alias.carbon
+
+library "alias";
+
+class C {}
+alias D = C;
+
+fn Foo(a: C);
+// CHECK:STDERR: fail_alias.carbon:[[@LINE+7]]:11: ERROR: Redeclaration syntax differs here.
+// CHECK:STDERR: fn Foo(a: D) {}
+// CHECK:STDERR:           ^
+// CHECK:STDERR: fail_alias.carbon:[[@LINE-4]]:11: Comparing with previous declaration here.
+// CHECK:STDERR: fn Foo(a: C);
+// CHECK:STDERR:           ^
+// CHECK:STDERR:
+fn Foo(a: D) {}
+
+// --- fail_deduced_alias.carbon
+
+library "deduced_alias";
+
+class C {}
+alias D = C;
+
+fn Foo[a: C]();
+// CHECK:STDERR: fail_deduced_alias.carbon:[[@LINE+7]]:11: ERROR: Redeclaration syntax differs here.
+// CHECK:STDERR: fn Foo[a: D]() {}
+// CHECK:STDERR:           ^
+// CHECK:STDERR: fail_deduced_alias.carbon:[[@LINE-4]]:11: Comparing with previous declaration here.
+// CHECK:STDERR: fn Foo[a: C]();
+// CHECK:STDERR:           ^
+// CHECK:STDERR:
+fn Foo[a: D]() {}
+
+// --- todo_fail_alias_in_return.carbon
+
+library "alias_in_return";
+
+class C {}
+alias D = C;
+
+fn Foo() -> C;
+fn Foo() -> D { return {}; }
+
+// --- alias_two_file.carbon
+
+library "alias_two_file";
+
+class C {}
+
+fn Foo(a: C);
+
+// --- todo_fail_alias_two_file.impl.carbon
+
+impl library "alias_two_file";
+
+alias D = C;
+
+fn Foo(a: D) {}
+
+// --- fail_repeat_const.carbon
+
+library "repeat_const";
+
+class C {}
+
+fn Foo(a: const C);
+// CHECK:STDERR: fail_repeat_const.carbon:[[@LINE+10]]:11: WARNING: `const` applied repeatedly to the same type has no additional effect.
+// CHECK:STDERR: fn Foo(a: const (const C)) {}
+// CHECK:STDERR:           ^~~~~~~~~~~~~~~
+// CHECK:STDERR:
+// CHECK:STDERR: fail_repeat_const.carbon:[[@LINE+6]]:17: ERROR: Redeclaration syntax differs here.
+// CHECK:STDERR: fn Foo(a: const (const C)) {}
+// CHECK:STDERR:                 ^
+// CHECK:STDERR: fail_repeat_const.carbon:[[@LINE-8]]:17: Comparing with previous declaration here.
+// CHECK:STDERR: fn Foo(a: const C);
+// CHECK:STDERR:                 ^
+fn Foo(a: const (const C)) {}
+
+// CHECK:STDOUT: --- basic.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = fn_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %.3: type = ptr_type %.1 [template]
+// CHECK:STDOUT:   %Bar.type: type = fn_type @Bar [template]
+// CHECK:STDOUT:   %Bar: %Bar.type = struct_value () [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .D = %D
+// CHECK:STDOUT:     .Foo = %Foo.decl.loc7
+// CHECK:STDOUT:     .Bar = %Bar.decl.loc10
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %C.ref.loc5: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %D: type = bind_alias D, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %Foo.decl.loc7: %Foo.type = fn_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc7: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc7_8.1: %C = param a
+// CHECK:STDOUT:     %a.loc7_8.2: %C = bind_name a, %a.loc7_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Foo.decl.loc8: %Foo.type = fn_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc8: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc8_8.1: %C = param a
+// CHECK:STDOUT:     @Foo.%a: %C = bind_name a, %a.loc8_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Bar.decl.loc10: %Bar.type = fn_decl @Bar [template = constants.%Bar] {
+// CHECK:STDOUT:     %D.ref.loc10: type = name_ref D, %D [template = constants.%C]
+// CHECK:STDOUT:     %a.loc10_8.1: %C = param a
+// CHECK:STDOUT:     %a.loc10_8.2: %C = bind_name a, %a.loc10_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Bar.decl.loc11: %Bar.type = fn_decl @Bar [template = constants.%Bar] {
+// CHECK:STDOUT:     %D.ref.loc11: type = name_ref D, %D [template = constants.%C]
+// CHECK:STDOUT:     %a.loc11_8.1: %C = param a
+// CHECK:STDOUT:     @Bar.%a: %C = bind_name a, %a.loc11_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Foo(%a: %C) {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Bar(%a: %C) {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- spacing.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = fn_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %.3: type = ptr_type %.1 [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .Foo = %Foo.decl.loc6
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %Foo.decl.loc6: %Foo.type = fn_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc6: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc6_14.1: %C = param a
+// CHECK:STDOUT:     %a.loc6_14.2: %C = bind_name a, %a.loc6_14.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Foo.decl.loc7: %Foo.type = fn_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc7: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc7_10.1: %C = param a
+// CHECK:STDOUT:     @Foo.%a: %C = bind_name a, %a.loc7_10.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Foo[](%a: %C) {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_parens.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = fn_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %.type: type = fn_type @.1 [template]
+// CHECK:STDOUT:   %.3: %.type = struct_value () [template]
+// CHECK:STDOUT:   %.4: type = ptr_type %.1 [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = fn_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc6: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc6_8.1: %C = param a
+// CHECK:STDOUT:     @Foo.%a: %C = bind_name a, %a.loc6_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.decl: %.type = fn_decl @.1 [template = constants.%.3] {
+// CHECK:STDOUT:     %C.ref.loc14: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc14_8.1: %C = param a
+// CHECK:STDOUT:     @.1.%a: %C = bind_name a, %a.loc14_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Foo(%a: %C);
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @.1(%a: %C) {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- todo_fail_raw_identifier.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = fn_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %.3: type = ptr_type %.1 [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .Foo = %Foo.decl.loc6
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %Foo.decl.loc6: %Foo.type = fn_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc6: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc6_8.1: %C = param a
+// CHECK:STDOUT:     %a.loc6_8.2: %C = bind_name a, %a.loc6_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Foo.decl.loc7: %Foo.type = fn_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc7: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc7_8.1: %C = param a
+// CHECK:STDOUT:     @Foo.%a: %C = bind_name a, %a.loc7_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Foo(%a: %C) {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- two_file.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = fn_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %Bar.type: type = fn_type @Bar [template]
+// CHECK:STDOUT:   %Bar: %Bar.type = struct_value () [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .D = %D
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:     .Bar = %Bar.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %C.ref.loc5: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %D: type = bind_alias D, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = fn_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc7: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc7_8.1: %C = param a
+// CHECK:STDOUT:     @Foo.%a: %C = bind_name a, %a.loc7_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Bar.decl: %Bar.type = fn_decl @Bar [template = constants.%Bar] {
+// CHECK:STDOUT:     %D.ref: type = name_ref D, %D [template = constants.%C]
+// CHECK:STDOUT:     %a.loc8_8.1: %C = param a
+// CHECK:STDOUT:     @Bar.%a: %C = bind_name a, %a.loc8_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Foo(%a: %C);
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Bar(%a: %C);
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- two_file.impl.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = fn_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %.3: type = ptr_type %.1 [template]
+// CHECK:STDOUT:   %Bar.type: type = fn_type @Bar [template]
+// CHECK:STDOUT:   %Bar: %Bar.type = struct_value () [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//two_file, inst+1, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.2: type = import_ref Main//two_file, inst+5, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.3: %Foo.type = import_ref Main//two_file, inst+9, loaded [template = constants.%Foo]
+// CHECK:STDOUT:   %import_ref.4: %Bar.type = import_ref Main//two_file, inst+16, loaded [template = constants.%Bar]
+// CHECK:STDOUT:   %import_ref.5 = import_ref Main//two_file, inst+2, unloaded
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = imports.%import_ref.1
+// CHECK:STDOUT:     .D = imports.%import_ref.2
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:     .Bar = %Bar.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %default.import.loc2_6.1 = import <invalid>
+// CHECK:STDOUT:   %default.import.loc2_6.2 = import <invalid>
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = fn_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref: type = name_ref C, imports.%import_ref.1 [template = constants.%C]
+// CHECK:STDOUT:     %a.loc4_8.1: %C = param a
+// CHECK:STDOUT:     @Foo.%a: %C = bind_name a, %a.loc4_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Bar.decl: %Bar.type = fn_decl @Bar [template = constants.%Bar] {
+// CHECK:STDOUT:     %D.ref: type = name_ref D, imports.%import_ref.2 [template = constants.%C]
+// CHECK:STDOUT:     %a.loc5_8.1: %C = param a
+// CHECK:STDOUT:     @Bar.%a: %C = bind_name a, %a.loc5_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = imports.%import_ref.5
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Foo(%a: %C) {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Bar(%a: %C) {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_name_mismatch.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = fn_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %.type: type = fn_type @.1 [template]
+// CHECK:STDOUT:   %.3: %.type = struct_value () [template]
+// CHECK:STDOUT:   %.4: type = ptr_type %.1 [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .D = %D
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %C.ref.loc5: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %D: type = bind_alias D, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = fn_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc7: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc7_8.1: %C = param a
+// CHECK:STDOUT:     @Foo.%a: %C = bind_name a, %a.loc7_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.decl: %.type = fn_decl @.1 [template = constants.%.3] {
+// CHECK:STDOUT:     %D.ref: type = name_ref D, %D [template = constants.%C]
+// CHECK:STDOUT:     %b.loc15_8.1: %C = param b
+// CHECK:STDOUT:     @.1.%b: %C = bind_name b, %b.loc15_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Foo(%a: %C);
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @.1(%b: %C) {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_alias.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = fn_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %.type: type = fn_type @.1 [template]
+// CHECK:STDOUT:   %.3: %.type = struct_value () [template]
+// CHECK:STDOUT:   %.4: type = ptr_type %.1 [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .D = %D
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %C.ref.loc5: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %D: type = bind_alias D, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = fn_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc7: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc7_8.1: %C = param a
+// CHECK:STDOUT:     @Foo.%a: %C = bind_name a, %a.loc7_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.decl: %.type = fn_decl @.1 [template = constants.%.3] {
+// CHECK:STDOUT:     %D.ref: type = name_ref D, %D [template = constants.%C]
+// CHECK:STDOUT:     %a.loc15_8.1: %C = param a
+// CHECK:STDOUT:     @.1.%a: %C = bind_name a, %a.loc15_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Foo(%a: %C);
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @.1(%a: %C) {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_deduced_alias.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = fn_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %.type: type = fn_type @.1 [template]
+// CHECK:STDOUT:   %.3: %.type = struct_value () [template]
+// CHECK:STDOUT:   %.4: type = ptr_type %.1 [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .D = %D
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %C.ref.loc5: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %D: type = bind_alias D, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = fn_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc7: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc7_8.1: %C = param a
+// CHECK:STDOUT:     @Foo.%a: %C = bind_name a, %a.loc7_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.decl: %.type = fn_decl @.1 [template = constants.%.3] {
+// CHECK:STDOUT:     %D.ref: type = name_ref D, %D [template = constants.%C]
+// CHECK:STDOUT:     %a.loc15_8.1: %C = param a
+// CHECK:STDOUT:     @.1.%a: %C = bind_name a, %a.loc15_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Foo[%a: %C]();
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @.1[%a: %C]() {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- todo_fail_alias_in_return.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = fn_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %.3: type = ptr_type %.1 [template]
+// CHECK:STDOUT:   %struct: %C = struct_value () [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .D = %D
+// CHECK:STDOUT:     .Foo = %Foo.decl.loc7
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %C.ref.loc5: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %D: type = bind_alias D, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %Foo.decl.loc7: %Foo.type = fn_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc7: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %return.var.loc7: ref %C = var <return slot>
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Foo.decl.loc8: %Foo.type = fn_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %D.ref: type = name_ref D, %D [template = constants.%C]
+// CHECK:STDOUT:     @Foo.%return: ref %C = var <return slot>
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Foo() -> %return: %C {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %.loc8_25.1: %.1 = struct_literal ()
+// CHECK:STDOUT:   %.loc8_25.2: init %C = class_init (), %return [template = constants.%struct]
+// CHECK:STDOUT:   %.loc8_26: init %C = converted %.loc8_25.1, %.loc8_25.2 [template = constants.%struct]
+// CHECK:STDOUT:   return %.loc8_26 to %return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- alias_two_file.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = fn_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = fn_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc6_8.1: %C = param a
+// CHECK:STDOUT:     @Foo.%a: %C = bind_name a, %a.loc6_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Foo(%a: %C);
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- todo_fail_alias_two_file.impl.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = fn_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %.3: type = ptr_type %.1 [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//alias_two_file, inst+1, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.2: %Foo.type = import_ref Main//alias_two_file, inst+7, loaded [template = constants.%Foo]
+// CHECK:STDOUT:   %import_ref.3 = import_ref Main//alias_two_file, inst+2, unloaded
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = imports.%import_ref.1
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:     .D = %D
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %default.import.loc2_6.1 = import <invalid>
+// CHECK:STDOUT:   %default.import.loc2_6.2 = import <invalid>
+// CHECK:STDOUT:   %C.ref: type = name_ref C, imports.%import_ref.1 [template = constants.%C]
+// CHECK:STDOUT:   %D: type = bind_alias D, imports.%import_ref.1 [template = constants.%C]
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = fn_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %D.ref: type = name_ref D, %D [template = constants.%C]
+// CHECK:STDOUT:     %a.loc6_8.1: %C = param a
+// CHECK:STDOUT:     @Foo.%a: %C = bind_name a, %a.loc6_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = imports.%import_ref.3
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Foo(%a: %C) {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_repeat_const.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %.2: type = const_type %C [template]
+// CHECK:STDOUT:   %Foo.type: type = fn_type @Foo [template]
+// CHECK:STDOUT:   %.3: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %.type: type = fn_type @.1 [template]
+// CHECK:STDOUT:   %.4: %.type = struct_value () [template]
+// CHECK:STDOUT:   %.5: type = ptr_type %.1 [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = fn_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc6: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %.loc6: type = const_type %C [template = constants.%.2]
+// CHECK:STDOUT:     %a.loc6_8.1: %.2 = param a
+// CHECK:STDOUT:     @Foo.%a: %.2 = bind_name a, %a.loc6_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.decl: %.type = fn_decl @.1 [template = constants.%.4] {
+// CHECK:STDOUT:     %C.ref.loc17: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %.loc17_18: type = const_type %C [template = constants.%.2]
+// CHECK:STDOUT:     %.loc17_11: type = const_type %.2 [template = constants.%.2]
+// CHECK:STDOUT:     %a.loc17_8.1: %.2 = param a
+// CHECK:STDOUT:     @.1.%a: %.2 = bind_name a, %a.loc17_8.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Foo(%a: %.2);
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @.1(%a: %.2) {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:

+ 795 - 0
toolchain/check/testdata/interface/no_prelude/syntactic_merge.carbon

@@ -0,0 +1,795 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// AUTOUPDATE
+// TIP: To test this file alone, run:
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interface/no_prelude/syntactic_merge.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interface/no_prelude/syntactic_merge.carbon
+
+// --- basic.carbon
+
+library "basic";
+
+class C {}
+alias D = C;
+
+interface Foo(a: C);
+interface Foo(a: C) {}
+
+interface Bar(a: D);
+interface Bar(a: D) {}
+
+// --- spacing.carbon
+
+library "spacing";
+
+class C {}
+
+interface Foo [ ] ( a : C );
+interface Foo[](a: C) {}
+
+// --- fail_parens.carbon
+
+library "parens";
+
+class C {}
+
+interface Foo(a: C);
+// CHECK:STDERR: fail_parens.carbon:[[@LINE+7]]:18: ERROR: Redeclaration syntax differs here.
+// CHECK:STDERR: interface Foo(a: (C)) {}
+// CHECK:STDERR:                  ^
+// CHECK:STDERR: fail_parens.carbon:[[@LINE-4]]:18: Comparing with previous declaration here.
+// CHECK:STDERR: interface Foo(a: C);
+// CHECK:STDERR:                  ^
+// CHECK:STDERR:
+interface Foo(a: (C)) {}
+
+// --- todo_fail_raw_identifier.carbon
+
+library "raw_identifier";
+
+class C {}
+
+interface Foo(a: C);
+interface Foo(a: r#C) {}
+
+// --- two_file.carbon
+
+library "two_file";
+
+class C {}
+alias D = C;
+
+interface Foo(a: C);
+interface Bar(a: D);
+
+// --- fail_todo_two_file.impl.carbon
+
+impl library "two_file";
+
+// CHECK:STDERR: fail_todo_two_file.impl.carbon:[[@LINE+10]]:1: ERROR: Duplicate name being declared in the same scope.
+// CHECK:STDERR: interface Foo(a: C) {}
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR: fail_todo_two_file.impl.carbon:[[@LINE-5]]:6: In import.
+// CHECK:STDERR: impl library "two_file";
+// CHECK:STDERR:      ^~~~~~~
+// CHECK:STDERR: two_file.carbon:7:1: Name is previously declared here.
+// CHECK:STDERR: interface Foo(a: C);
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR:
+interface Foo(a: C) {}
+// CHECK:STDERR: fail_todo_two_file.impl.carbon:[[@LINE+10]]:1: ERROR: Duplicate name being declared in the same scope.
+// CHECK:STDERR: interface Bar(a: D) {}
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR: fail_todo_two_file.impl.carbon:[[@LINE-16]]:6: In import.
+// CHECK:STDERR: impl library "two_file";
+// CHECK:STDERR:      ^~~~~~~
+// CHECK:STDERR: two_file.carbon:8:1: Name is previously declared here.
+// CHECK:STDERR: interface Bar(a: D);
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR:
+interface Bar(a: D) {}
+
+// --- fail_name_mismatch.carbon
+
+library "name_mismatch";
+
+class C {}
+alias D = C;
+
+interface Foo(a: C);
+// CHECK:STDERR: fail_name_mismatch.carbon:[[@LINE+7]]:15: ERROR: Redeclaration differs at parameter 1.
+// CHECK:STDERR: interface Foo(b: D) {}
+// CHECK:STDERR:               ^
+// CHECK:STDERR: fail_name_mismatch.carbon:[[@LINE-4]]:15: Previous declaration's corresponding parameter here.
+// CHECK:STDERR: interface Foo(a: C);
+// CHECK:STDERR:               ^
+// CHECK:STDERR:
+interface Foo(b: D) {}
+
+// --- fail_alias.carbon
+
+library "alias";
+
+class C {}
+alias D = C;
+
+interface Foo(a: C);
+// CHECK:STDERR: fail_alias.carbon:[[@LINE+7]]:18: ERROR: Redeclaration syntax differs here.
+// CHECK:STDERR: interface Foo(a: D) {}
+// CHECK:STDERR:                  ^
+// CHECK:STDERR: fail_alias.carbon:[[@LINE-4]]:18: Comparing with previous declaration here.
+// CHECK:STDERR: interface Foo(a: C);
+// CHECK:STDERR:                  ^
+// CHECK:STDERR:
+interface Foo(a: D) {}
+
+// --- fail_deduced_alias.carbon
+
+library "deduced_alias";
+
+class C {}
+alias D = C;
+
+interface Foo[a: C]();
+// CHECK:STDERR: fail_deduced_alias.carbon:[[@LINE+7]]:18: ERROR: Redeclaration syntax differs here.
+// CHECK:STDERR: interface Foo[a: D]() {}
+// CHECK:STDERR:                  ^
+// CHECK:STDERR: fail_deduced_alias.carbon:[[@LINE-4]]:18: Comparing with previous declaration here.
+// CHECK:STDERR: interface Foo[a: C]();
+// CHECK:STDERR:                  ^
+// CHECK:STDERR:
+interface Foo[a: D]() {}
+
+// --- alias_two_file.carbon
+
+library "alias_two_file";
+
+class C {}
+
+interface Foo(a: C);
+
+// --- fail_alias_two_file.impl.carbon
+
+impl library "alias_two_file";
+
+alias D = C;
+
+// TODO: This fails because importing interfaces doesn't work well. It should
+// fail due to `C` versus `D`, but may succeed if importing interfaces is fixed
+// before syntax matching on imports is supported.
+// CHECK:STDERR: fail_alias_two_file.impl.carbon:[[@LINE+10]]:1: ERROR: Duplicate name being declared in the same scope.
+// CHECK:STDERR: interface Foo(a: D) {}
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR: fail_alias_two_file.impl.carbon:[[@LINE-10]]:6: In import.
+// CHECK:STDERR: impl library "alias_two_file";
+// CHECK:STDERR:      ^~~~~~~
+// CHECK:STDERR: alias_two_file.carbon:6:1: Name is previously declared here.
+// CHECK:STDERR: interface Foo(a: C);
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~
+// CHECK:STDERR:
+interface Foo(a: D) {}
+
+// --- fail_repeat_const.carbon
+
+library "repeat_const";
+
+class C {}
+
+interface Foo(a: const C);
+// CHECK:STDERR: fail_repeat_const.carbon:[[@LINE+10]]:18: WARNING: `const` applied repeatedly to the same type has no additional effect.
+// CHECK:STDERR: interface Foo(a: const (const C)) {}
+// CHECK:STDERR:                  ^~~~~~~~~~~~~~~
+// CHECK:STDERR:
+// CHECK:STDERR: fail_repeat_const.carbon:[[@LINE+6]]:24: ERROR: Redeclaration syntax differs here.
+// CHECK:STDERR: interface Foo(a: const (const C)) {}
+// CHECK:STDERR:                        ^
+// CHECK:STDERR: fail_repeat_const.carbon:[[@LINE-8]]:24: Comparing with previous declaration here.
+// CHECK:STDERR: interface Foo(a: const C);
+// CHECK:STDERR:                        ^
+interface Foo(a: const (const C)) {}
+
+// CHECK:STDOUT: --- basic.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = generic_interface_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %.3: type = interface_type @Foo [template]
+// CHECK:STDOUT:   %Self.1: %.3 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT:   %Bar.type: type = generic_interface_type @Bar [template]
+// CHECK:STDOUT:   %Bar: %Bar.type = struct_value () [template]
+// CHECK:STDOUT:   %.4: type = interface_type @Bar [template]
+// CHECK:STDOUT:   %Self.2: %.4 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .D = %D
+// CHECK:STDOUT:     .Foo = %Foo.decl.loc7
+// CHECK:STDOUT:     .Bar = %Bar.decl.loc10
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %C.ref.loc5: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %D: type = bind_alias D, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %Foo.decl.loc7: %Foo.type = interface_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc7: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc7_15.1: %C = param a
+// CHECK:STDOUT:     %a.loc7_15.2: %C = bind_name a, %a.loc7_15.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Foo.decl.loc8: %Foo.type = interface_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc8: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc8_15.1: %C = param a
+// CHECK:STDOUT:     %a.loc8_15.2: %C = bind_name a, %a.loc8_15.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Bar.decl.loc10: %Bar.type = interface_decl @Bar [template = constants.%Bar] {
+// CHECK:STDOUT:     %D.ref.loc10: type = name_ref D, %D [template = constants.%C]
+// CHECK:STDOUT:     %a.loc10_15.1: %C = param a
+// CHECK:STDOUT:     %a.loc10_15.2: %C = bind_name a, %a.loc10_15.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Bar.decl.loc11: %Bar.type = interface_decl @Bar [template = constants.%Bar] {
+// CHECK:STDOUT:     %D.ref.loc11: type = name_ref D, %D [template = constants.%C]
+// CHECK:STDOUT:     %a.loc11_15.1: %C = param a
+// CHECK:STDOUT:     %a.loc11_15.2: %C = bind_name a, %a.loc11_15.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @Foo {
+// CHECK:STDOUT:   %Self: %.3 = bind_symbolic_name Self 0 [symbolic = constants.%Self.1]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   witness = ()
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @Bar {
+// CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 0 [symbolic = constants.%Self.2]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   witness = ()
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- spacing.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = generic_interface_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %.3: type = interface_type @Foo [template]
+// CHECK:STDOUT:   %Self: %.3 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .Foo = %Foo.decl.loc6
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %Foo.decl.loc6: %Foo.type = interface_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc6: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc6_21.1: %C = param a
+// CHECK:STDOUT:     %a.loc6_21.2: %C = bind_name a, %a.loc6_21.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Foo.decl.loc7: %Foo.type = interface_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc7: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc7_17.1: %C = param a
+// CHECK:STDOUT:     %a.loc7_17.2: %C = bind_name a, %a.loc7_17.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @Foo {
+// CHECK:STDOUT:   %Self: %.3 = bind_symbolic_name Self 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   witness = ()
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_parens.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = generic_interface_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %.type: type = generic_interface_type @.1 [template]
+// CHECK:STDOUT:   %.3: %.type = struct_value () [template]
+// CHECK:STDOUT:   %.4: type = interface_type @.1 [template]
+// CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = interface_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc6: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc6_15.1: %C = param a
+// CHECK:STDOUT:     %a.loc6_15.2: %C = bind_name a, %a.loc6_15.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.decl: %.type = interface_decl @.1 [template = constants.%.3] {
+// CHECK:STDOUT:     %C.ref.loc14: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc14_15.1: %C = param a
+// CHECK:STDOUT:     %a.loc14_15.2: %C = bind_name a, %a.loc14_15.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @Foo;
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @.1 {
+// CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   witness = ()
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- todo_fail_raw_identifier.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = generic_interface_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %.3: type = interface_type @Foo [template]
+// CHECK:STDOUT:   %Self: %.3 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .Foo = %Foo.decl.loc6
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %Foo.decl.loc6: %Foo.type = interface_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc6: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc6_15.1: %C = param a
+// CHECK:STDOUT:     %a.loc6_15.2: %C = bind_name a, %a.loc6_15.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Foo.decl.loc7: %Foo.type = interface_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc7: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc7_15.1: %C = param a
+// CHECK:STDOUT:     %a.loc7_15.2: %C = bind_name a, %a.loc7_15.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @Foo {
+// CHECK:STDOUT:   %Self: %.3 = bind_symbolic_name Self 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   witness = ()
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- two_file.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = generic_interface_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %Bar.type: type = generic_interface_type @Bar [template]
+// CHECK:STDOUT:   %Bar: %Bar.type = struct_value () [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .D = %D
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:     .Bar = %Bar.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %C.ref.loc5: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %D: type = bind_alias D, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = interface_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc7: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc7_15.1: %C = param a
+// CHECK:STDOUT:     %a.loc7_15.2: %C = bind_name a, %a.loc7_15.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Bar.decl: %Bar.type = interface_decl @Bar [template = constants.%Bar] {
+// CHECK:STDOUT:     %D.ref: type = name_ref D, %D [template = constants.%C]
+// CHECK:STDOUT:     %a.loc8_15.1: %C = param a
+// CHECK:STDOUT:     %a.loc8_15.2: %C = bind_name a, %a.loc8_15.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @Foo;
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @Bar;
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_todo_two_file.impl.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = generic_interface_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %.type.1: type = generic_interface_type @.1 [template]
+// CHECK:STDOUT:   %.3: %.type.1 = struct_value () [template]
+// CHECK:STDOUT:   %.4: type = interface_type @.1 [template]
+// CHECK:STDOUT:   %Self.1: %.4 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT:   %Bar.type: type = generic_interface_type @Bar [template]
+// CHECK:STDOUT:   %Bar: %Bar.type = struct_value () [template]
+// CHECK:STDOUT:   %.type.2: type = generic_interface_type @.2 [template]
+// CHECK:STDOUT:   %.5: %.type.2 = struct_value () [template]
+// CHECK:STDOUT:   %.6: type = interface_type @.2 [template]
+// CHECK:STDOUT:   %Self.2: %.6 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//two_file, inst+1, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.2: type = import_ref Main//two_file, inst+5, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.3: %Foo.type = import_ref Main//two_file, inst+9, loaded [template = constants.%Foo]
+// CHECK:STDOUT:   %import_ref.4: %Bar.type = import_ref Main//two_file, inst+16, loaded [template = constants.%Bar]
+// CHECK:STDOUT:   %import_ref.5 = import_ref Main//two_file, inst+2, unloaded
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = imports.%import_ref.1
+// CHECK:STDOUT:     .D = imports.%import_ref.2
+// CHECK:STDOUT:     .Foo = imports.%import_ref.3
+// CHECK:STDOUT:     .Bar = imports.%import_ref.4
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %default.import.loc2_6.1 = import <invalid>
+// CHECK:STDOUT:   %default.import.loc2_6.2 = import <invalid>
+// CHECK:STDOUT:   %.decl.loc14: %.type.1 = interface_decl @.1 [template = constants.%.3] {
+// CHECK:STDOUT:     %C.ref: type = name_ref C, imports.%import_ref.1 [template = constants.%C]
+// CHECK:STDOUT:     %a.loc14_15.1: %C = param a
+// CHECK:STDOUT:     %a.loc14_15.2: %C = bind_name a, %a.loc14_15.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.decl.loc25: %.type.2 = interface_decl @.2 [template = constants.%.5] {
+// CHECK:STDOUT:     %D.ref: type = name_ref D, imports.%import_ref.2 [template = constants.%C]
+// CHECK:STDOUT:     %a.loc25_15.1: %C = param a
+// CHECK:STDOUT:     %a.loc25_15.2: %C = bind_name a, %a.loc25_15.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @Foo;
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @.1 {
+// CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 0 [symbolic = constants.%Self.1]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   witness = ()
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @Bar;
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @.2 {
+// CHECK:STDOUT:   %Self: %.6 = bind_symbolic_name Self 0 [symbolic = constants.%Self.2]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   witness = ()
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = imports.%import_ref.5
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_name_mismatch.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = generic_interface_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %.type: type = generic_interface_type @.1 [template]
+// CHECK:STDOUT:   %.3: %.type = struct_value () [template]
+// CHECK:STDOUT:   %.4: type = interface_type @.1 [template]
+// CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .D = %D
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %C.ref.loc5: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %D: type = bind_alias D, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = interface_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc7: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc7_15.1: %C = param a
+// CHECK:STDOUT:     %a.loc7_15.2: %C = bind_name a, %a.loc7_15.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.decl: %.type = interface_decl @.1 [template = constants.%.3] {
+// CHECK:STDOUT:     %D.ref: type = name_ref D, %D [template = constants.%C]
+// CHECK:STDOUT:     %b.loc15_15.1: %C = param b
+// CHECK:STDOUT:     %b.loc15_15.2: %C = bind_name b, %b.loc15_15.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @Foo;
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @.1 {
+// CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   witness = ()
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_alias.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = generic_interface_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %.type: type = generic_interface_type @.1 [template]
+// CHECK:STDOUT:   %.3: %.type = struct_value () [template]
+// CHECK:STDOUT:   %.4: type = interface_type @.1 [template]
+// CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .D = %D
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %C.ref.loc5: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %D: type = bind_alias D, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = interface_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc7: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc7_15.1: %C = param a
+// CHECK:STDOUT:     %a.loc7_15.2: %C = bind_name a, %a.loc7_15.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.decl: %.type = interface_decl @.1 [template = constants.%.3] {
+// CHECK:STDOUT:     %D.ref: type = name_ref D, %D [template = constants.%C]
+// CHECK:STDOUT:     %a.loc15_15.1: %C = param a
+// CHECK:STDOUT:     %a.loc15_15.2: %C = bind_name a, %a.loc15_15.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @Foo;
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @.1 {
+// CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   witness = ()
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_deduced_alias.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = generic_interface_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %.type: type = generic_interface_type @.1 [template]
+// CHECK:STDOUT:   %.3: %.type = struct_value () [template]
+// CHECK:STDOUT:   %.4: type = interface_type @.1 [template]
+// CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .D = %D
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %C.ref.loc5: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %D: type = bind_alias D, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = interface_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc7: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc7_15.1: %C = param a
+// CHECK:STDOUT:     %a.loc7_15.2: %C = bind_name a, %a.loc7_15.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.decl: %.type = interface_decl @.1 [template = constants.%.3] {
+// CHECK:STDOUT:     %D.ref: type = name_ref D, %D [template = constants.%C]
+// CHECK:STDOUT:     %a.loc15_15.1: %C = param a
+// CHECK:STDOUT:     %a.loc15_15.2: %C = bind_name a, %a.loc15_15.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @Foo;
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @.1 {
+// CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   witness = ()
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- alias_two_file.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = generic_interface_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = interface_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %a.loc6_15.1: %C = param a
+// CHECK:STDOUT:     %a.loc6_15.2: %C = bind_name a, %a.loc6_15.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @Foo;
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_alias_two_file.impl.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %Foo.type: type = generic_interface_type @Foo [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %.type: type = generic_interface_type @.1 [template]
+// CHECK:STDOUT:   %.3: %.type = struct_value () [template]
+// CHECK:STDOUT:   %.4: type = interface_type @.1 [template]
+// CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %import_ref.1: type = import_ref Main//alias_two_file, inst+1, loaded [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.2: %Foo.type = import_ref Main//alias_two_file, inst+7, loaded [template = constants.%Foo]
+// CHECK:STDOUT:   %import_ref.3 = import_ref Main//alias_two_file, inst+2, unloaded
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = imports.%import_ref.1
+// CHECK:STDOUT:     .Foo = imports.%import_ref.2
+// CHECK:STDOUT:     .D = %D
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %default.import.loc2_6.1 = import <invalid>
+// CHECK:STDOUT:   %default.import.loc2_6.2 = import <invalid>
+// CHECK:STDOUT:   %C.ref: type = name_ref C, imports.%import_ref.1 [template = constants.%C]
+// CHECK:STDOUT:   %D: type = bind_alias D, imports.%import_ref.1 [template = constants.%C]
+// CHECK:STDOUT:   %.decl: %.type = interface_decl @.1 [template = constants.%.3] {
+// CHECK:STDOUT:     %D.ref: type = name_ref D, %D [template = constants.%C]
+// CHECK:STDOUT:     %a.loc19_15.1: %C = param a
+// CHECK:STDOUT:     %a.loc19_15.2: %C = bind_name a, %a.loc19_15.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @Foo;
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @.1 {
+// CHECK:STDOUT:   %Self: %.4 = bind_symbolic_name Self 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   witness = ()
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = imports.%import_ref.3
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_repeat_const.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %.2: type = const_type %C [template]
+// CHECK:STDOUT:   %Foo.type: type = generic_interface_type @Foo [template]
+// CHECK:STDOUT:   %.3: type = tuple_type () [template]
+// CHECK:STDOUT:   %Foo: %Foo.type = struct_value () [template]
+// CHECK:STDOUT:   %.type: type = generic_interface_type @.1 [template]
+// CHECK:STDOUT:   %.4: %.type = struct_value () [template]
+// CHECK:STDOUT:   %.5: type = interface_type @.1 [template]
+// CHECK:STDOUT:   %Self: %.5 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .Foo = %Foo.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %Foo.decl: %Foo.type = interface_decl @Foo [template = constants.%Foo] {
+// CHECK:STDOUT:     %C.ref.loc6: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %.loc6: type = const_type %C [template = constants.%.2]
+// CHECK:STDOUT:     %a.loc6_15.1: %.2 = param a
+// CHECK:STDOUT:     %a.loc6_15.2: %.2 = bind_name a, %a.loc6_15.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.decl: %.type = interface_decl @.1 [template = constants.%.4] {
+// CHECK:STDOUT:     %C.ref.loc17: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:     %.loc17_25: type = const_type %C [template = constants.%.2]
+// CHECK:STDOUT:     %.loc17_18: type = const_type %.2 [template = constants.%.2]
+// CHECK:STDOUT:     %a.loc17_15.1: %.2 = param a
+// CHECK:STDOUT:     %a.loc17_15.2: %.2 = bind_name a, %a.loc17_15.1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @Foo;
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @.1 {
+// CHECK:STDOUT:   %Self: %.5 = bind_symbolic_name Self 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   witness = ()
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:

+ 2 - 0
toolchain/diagnostics/diagnostic_kind.def

@@ -165,6 +165,8 @@ CARBON_DIAGNOSTIC_KIND(RedeclParamCountDiffers)
 CARBON_DIAGNOSTIC_KIND(RedeclParamCountPrevious)
 CARBON_DIAGNOSTIC_KIND(RedeclParamCountPrevious)
 CARBON_DIAGNOSTIC_KIND(RedeclParamDiffers)
 CARBON_DIAGNOSTIC_KIND(RedeclParamDiffers)
 CARBON_DIAGNOSTIC_KIND(RedeclParamPrevious)
 CARBON_DIAGNOSTIC_KIND(RedeclParamPrevious)
+CARBON_DIAGNOSTIC_KIND(RedeclParamSyntaxDiffers)
+CARBON_DIAGNOSTIC_KIND(RedeclParamSyntaxPrevious)
 
 
 // Function call checking.
 // Function call checking.
 CARBON_DIAGNOSTIC_KIND(AddrSelfIsNonRef)
 CARBON_DIAGNOSTIC_KIND(AddrSelfIsNonRef)

+ 7 - 0
toolchain/parse/tree.cpp

@@ -32,6 +32,13 @@ auto Tree::postorder(NodeId n) const
       PostorderIterator(NodeId(end_index)));
       PostorderIterator(NodeId(end_index)));
 }
 }
 
 
+auto Tree::postorder(NodeId begin, NodeId end) const
+    -> llvm::iterator_range<PostorderIterator> {
+  CARBON_CHECK(begin.is_valid() && end.is_valid());
+  return llvm::iterator_range<PostorderIterator>(
+      PostorderIterator(begin), PostorderIterator(NodeId(end.index + 1)));
+}
+
 auto Tree::children(NodeId n) const -> llvm::iterator_range<SiblingIterator> {
 auto Tree::children(NodeId n) const -> llvm::iterator_range<SiblingIterator> {
   CARBON_CHECK(n.is_valid());
   CARBON_CHECK(n.is_valid());
   int end_index = n.index - node_impls_[n.index].subtree_size;
   int end_index = n.index - node_impls_[n.index].subtree_size;

+ 5 - 0
toolchain/parse/tree.h

@@ -118,6 +118,11 @@ class Tree : public Printable<Tree> {
   // descendants in depth-first postorder.
   // descendants in depth-first postorder.
   auto postorder(NodeId n) const -> llvm::iterator_range<PostorderIterator>;
   auto postorder(NodeId n) const -> llvm::iterator_range<PostorderIterator>;
 
 
+  // Returns an iterable range between the two parse tree nodes, in depth-first
+  // postorder. The range is inclusive of the bounds: [begin, end].
+  auto postorder(NodeId begin, NodeId end) const
+      -> llvm::iterator_range<PostorderIterator>;
+
   // Returns an iterable range over the direct children of a node in the parse
   // Returns an iterable range over the direct children of a node in the parse
   // tree. This is a forward range, but is constant time to increment. The order
   // tree. This is a forward range, but is constant time to increment. The order
   // of children is the same as would be found in a reverse postorder traversal.
   // of children is the same as would be found in a reverse postorder traversal.

+ 5 - 0
toolchain/sem_ir/class.h

@@ -42,6 +42,11 @@ struct Class : public Printable<Class> {
   NameScopeId parent_scope_id;
   NameScopeId parent_scope_id;
   // If this is a generic function, information about the generic.
   // If this is a generic function, information about the generic.
   GenericId generic_id;
   GenericId generic_id;
+  // Parse tree bounds for the parameters, including both implicit and explicit
+  // parameters. These will be compared to match between declaration and
+  // definition.
+  Parse::NodeId first_param_node_id;
+  Parse::NodeId last_param_node_id;
   // A block containing a single reference instruction per implicit parameter.
   // A block containing a single reference instruction per implicit parameter.
   InstBlockId implicit_param_refs_id;
   InstBlockId implicit_param_refs_id;
   // A block containing a single reference instruction per parameter.
   // A block containing a single reference instruction per parameter.

+ 5 - 0
toolchain/sem_ir/function.h

@@ -86,6 +86,11 @@ struct Function : public Printable<Function> {
   InstId decl_id;
   InstId decl_id;
   // If this is a generic function, information about the generic.
   // If this is a generic function, information about the generic.
   GenericId generic_id;
   GenericId generic_id;
+  // Parse tree bounds for the parameters, including both implicit and explicit
+  // parameters. These will be compared to match between declaration and
+  // definition.
+  Parse::NodeId first_param_node_id;
+  Parse::NodeId last_param_node_id;
   // A block containing a single reference instruction per implicit parameter.
   // A block containing a single reference instruction per implicit parameter.
   InstBlockId implicit_param_refs_id;
   InstBlockId implicit_param_refs_id;
   // A block containing a single reference instruction per parameter.
   // A block containing a single reference instruction per parameter.

+ 5 - 0
toolchain/sem_ir/interface.h

@@ -39,6 +39,11 @@ struct Interface : public Printable<Interface> {
   NameScopeId parent_scope_id;
   NameScopeId parent_scope_id;
   // If this is a generic function, information about the generic.
   // If this is a generic function, information about the generic.
   GenericId generic_id;
   GenericId generic_id;
+  // Parse tree bounds for the parameters, including both implicit and explicit
+  // parameters. These will be compared to match between declaration and
+  // definition.
+  Parse::NodeId first_param_node_id;
+  Parse::NodeId last_param_node_id;
   // A block containing a single reference instruction per implicit parameter.
   // A block containing a single reference instruction per implicit parameter.
   InstBlockId implicit_param_refs_id;
   InstBlockId implicit_param_refs_id;
   // A block containing a single reference instruction per parameter.
   // A block containing a single reference instruction per parameter.