Explorar el Código

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 hace 1 año
padre
commit
db022658c6

+ 8 - 6
toolchain/check/decl_name_stack.cpp

@@ -366,8 +366,9 @@ auto DeclNameStack::ResolveAsScope(const NameContext& name_context,
     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.
   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): {
       auto scope_id = resolved_inst.name_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;
       }
       if (scope.is_closed_import) {

+ 4 - 2
toolchain/check/function.cpp

@@ -13,9 +13,11 @@ namespace Carbon::Check {
 auto CheckFunctionTypeMatches(Context& context,
                               const SemIR::Function& new_function,
                               const SemIR::Function& prev_function,
-                              Substitutions substitutions) -> bool {
+                              Substitutions substitutions, bool check_syntax)
+    -> bool {
   if (!CheckRedeclParamsMatch(context, DeclParams(new_function),
-                              DeclParams(prev_function), substitutions)) {
+                              DeclParams(prev_function), substitutions,
+                              check_syntax)) {
     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
 // `prev_function`, applying the specified set of substitutions to the
 // 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,
                               const SemIR::Function& new_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
 // 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,
        .decl_id = SemIR::InstId::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,
        .param_refs_id = SemIR::InstBlockId::Empty,
        .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) {
+    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.param_refs_id = new_class.param_refs_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(),
       .parent_scope_id = name_context.parent_scope_id_for_new_inst(),
       .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,
       .param_refs_id = name.params_id,
       // `.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 {
   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;
   }
 
@@ -118,6 +119,8 @@ static auto MergeFunctionRedecl(Context& context, SemIRLoc new_loc,
     // Track the signature from the definition, so that IDs in the body
     // match IDs in the signature.
     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.param_refs_id = new_function.param_refs_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(),
       .decl_id = decl_id,
       .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,
       .param_refs_id = name.params_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 params_id =
       context.node_stack().Pop<Parse::NodeKind::ImplicitParamList>();
+  context.node_stack()
+      .PopAndDiscardSoloNodeId<Parse::NodeKind::ImplicitParamListStart>();
   context.node_stack().Push(node_id, params_id);
   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.
       if (CheckRedeclParamsMatch(
               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),
               DeclParams(context.interfaces().Get(
                   existing_interface_decl->interface_id)))) {
@@ -90,6 +91,8 @@ static auto BuildInterfaceDecl(Context& context,
         .name_id = name_context.name_id_for_new_inst(),
         .parent_scope_id = name_context.parent_scope_id_for_new_inst(),
         .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,
         .param_refs_id = name.params_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)
     -> 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(
       Parse::NodeKind::ImplicitParamListStart);
-  context.node_stack()
-      .PopAndDiscardSoloNodeId<Parse::NodeKind::ImplicitParamListStart>();
   context.node_stack().Push(node_id, refs_id);
   // The implicit parameter list's scope extends to the end of the following
   // parameter list.
@@ -40,10 +40,10 @@ auto HandleParseNode(Context& context, Parse::PatternListCommaId /*node_id*/)
 }
 
 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(
       Parse::NodeKind::TuplePatternStart);
-  context.node_stack()
-      .PopAndDiscardSoloNodeId<Parse::NodeKind::TuplePatternStart>();
   context.node_stack().Push(node_id, refs_id);
   return true;
 }

+ 2 - 1
toolchain/check/impl.cpp

@@ -54,7 +54,8 @@ static auto CheckAssociatedFunctionImplementation(
   // synthesize a suitable thunk.
   if (!CheckFunctionTypeMatches(
           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 impl_decl_id;

+ 6 - 0
toolchain/check/import_ref.cpp

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

+ 82 - 3
toolchain/check/merge.cpp

@@ -268,9 +268,79 @@ static auto CheckRedeclParams(Context& context, SemIRLoc new_decl_loc,
   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,
                             const DeclParams& prev_entity,
-                            Substitutions substitutions) -> bool {
+                            Substitutions substitutions, bool check_syntax)
+    -> bool {
   if (EntityHasParamError(context, new_entity) ||
       EntityHasParamError(context, prev_entity)) {
     return false;
@@ -278,12 +348,21 @@ auto CheckRedeclParamsMatch(Context& context, const DeclParams& new_entity,
   if (!CheckRedeclParams(context, new_entity.loc,
                          new_entity.implicit_param_refs_id, prev_entity.loc,
                          prev_entity.implicit_param_refs_id, "implicit ",
-                         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, "",
                          substitutions)) {
     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;
 }
 

+ 16 - 3
toolchain/check/merge.h

@@ -47,17 +47,30 @@ struct DeclParams {
   template <typename Entity>
   explicit DeclParams(const Entity& entity)
       : 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),
         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)
       : 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),
         param_refs_id(params_id) {}
 
   // The location of the declaration of the entity.
   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
   // implicit parameter list.
   SemIR::InstBlockId implicit_param_refs_id;
@@ -71,8 +84,8 @@ struct DeclParams {
 // returns false.
 auto CheckRedeclParamsMatch(Context& context, const DeclParams& new_entity,
                             const DeclParams& prev_entity,
-                            Substitutions substitutions = Substitutions())
-    -> bool;
+                            Substitutions substitutions = Substitutions(),
+                            bool check_syntax = true) -> bool;
 
 }  // namespace Carbon::Check
 

+ 25 - 0
toolchain/check/name_component.cpp

@@ -9,15 +9,40 @@
 namespace Carbon::Check {
 
 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] =
       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] =
       context.node_stack()
           .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();
   return {
       .name_loc_id = name_loc_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_id =
           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;
   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.
   Parse::NodeId implicit_params_loc_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 Base.F[addr self: Base*]() {
+fn Base.F[addr self: Self*]() {
   (*self).a = 1;
 }
 
@@ -73,7 +73,7 @@ fn Call(p: Derived*) {
 // CHECK:STDOUT:   }
 // 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:     %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:     %self.loc17_16.1: %.3 = param self
 // 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(RedeclParamDiffers)
 CARBON_DIAGNOSTIC_KIND(RedeclParamPrevious)
+CARBON_DIAGNOSTIC_KIND(RedeclParamSyntaxDiffers)
+CARBON_DIAGNOSTIC_KIND(RedeclParamSyntaxPrevious)
 
 // Function call checking.
 CARBON_DIAGNOSTIC_KIND(AddrSelfIsNonRef)

+ 7 - 0
toolchain/parse/tree.cpp

@@ -32,6 +32,13 @@ auto Tree::postorder(NodeId n) const
       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> {
   CARBON_CHECK(n.is_valid());
   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.
   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
   // 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.

+ 5 - 0
toolchain/sem_ir/class.h

@@ -42,6 +42,11 @@ struct Class : public Printable<Class> {
   NameScopeId parent_scope_id;
   // If this is a generic function, information about the generic.
   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.
   InstBlockId implicit_param_refs_id;
   // 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;
   // If this is a generic function, information about the generic.
   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.
   InstBlockId implicit_param_refs_id;
   // 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;
   // If this is a generic function, information about the generic.
   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.
   InstBlockId implicit_param_refs_id;
   // A block containing a single reference instruction per parameter.