Ver Fonte

Add support for combining conflicting exported names. (#3954)

I think this is a key remaining bit of polish for intra-package exports.
Next I'm going to be dealing with cross-package exports, though I think
the fundamentals here will remain intact.

Extern declarations could cause issues for the current approach, but I
think that can be addressed separately. I don't think it's a fundamental
problem, more just incremental.

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Jon Ross-Perkins há 1 ano atrás
pai
commit
69c7012cbe

+ 74 - 15
toolchain/check/import.cpp

@@ -12,6 +12,7 @@
 #include "toolchain/parse/node_ids.h"
 #include "toolchain/sem_ir/file.h"
 #include "toolchain/sem_ir/ids.h"
+#include "toolchain/sem_ir/import_ir.h"
 #include "toolchain/sem_ir/inst.h"
 #include "toolchain/sem_ir/typed_insts.h"
 
@@ -216,6 +217,77 @@ static auto CopyEnclosingNameScopesFromImportIR(
   return scope_cursor;
 }
 
+// Returns the canonical IR inst for an entity. Returns an invalid ir_id for the
+// current IR.
+static auto GetCanonicalImportIRInst(Context& context,
+                                     const SemIR::File* cursor_ir,
+                                     SemIR::InstId cursor_inst_id)
+    -> SemIR::ImportIRInst {
+  while (true) {
+    auto inst = cursor_ir->insts().Get(cursor_inst_id);
+    CARBON_KIND_SWITCH(inst) {
+      case CARBON_KIND(SemIR::BindExport bind_export): {
+        cursor_inst_id = bind_export.value_id;
+        continue;
+      }
+      case SemIR::ImportRefLoaded::Kind:
+      case SemIR::ImportRefUnloaded::Kind: {
+        auto import_ref = inst.As<SemIR::AnyImportRef>();
+        auto import_ir_inst =
+            cursor_ir->import_ir_insts().Get(import_ref.import_ir_inst_id);
+        cursor_ir = cursor_ir->import_irs().Get(import_ir_inst.ir_id).sem_ir;
+        cursor_inst_id = import_ir_inst.inst_id;
+        continue;
+      }
+      default: {
+        auto ir_id = SemIR::ImportIRId::Invalid;
+        if (cursor_ir != &context.sem_ir()) {
+          // This uses AddImportIR in case it was indirectly found, which can
+          // happen with two or more steps of exports.
+          ir_id = AddImportIR(context, {.node_id = Parse::NodeId::Invalid,
+                                        .sem_ir = cursor_ir,
+                                        .is_export = false});
+        }
+        return {.ir_id = ir_id, .inst_id = cursor_inst_id};
+      }
+    }
+  }
+}
+
+// Adds an ImportRef for an entity, handling merging if needed.
+static auto AddImportRefOrMerge(Context& context, SemIR::ImportIRId ir_id,
+                                const SemIR::File& import_sem_ir,
+                                SemIR::InstId import_inst_id,
+                                SemIR::NameScopeId enclosing_scope_id,
+                                SemIR::NameId name_id) -> void {
+  // Leave a placeholder that the inst comes from the other IR.
+  auto& names = context.name_scopes().Get(enclosing_scope_id).names;
+  auto [it, success] = names.insert({name_id, SemIR::InstId::Invalid});
+  if (success) {
+    auto bind_name_id = context.bind_names().Add(
+        {.name_id = name_id,
+         .enclosing_scope_id = enclosing_scope_id,
+         .bind_index = SemIR::CompileTimeBindIndex::Invalid});
+    it->second = AddImportRef(
+        context, {.ir_id = ir_id, .inst_id = import_inst_id}, bind_name_id);
+    return;
+  }
+
+  auto prev_ir_inst =
+      GetCanonicalImportIRInst(context, &context.sem_ir(), it->second);
+  auto new_ir_inst =
+      GetCanonicalImportIRInst(context, &import_sem_ir, import_inst_id);
+
+  // Diagnose if the imported instructions aren't equal. However, then we need
+  // to form an instruction for the duplicate diagnostic.
+  if (prev_ir_inst != new_ir_inst) {
+    auto conflict_id =
+        AddImportRef(context, {.ir_id = ir_id, .inst_id = import_inst_id},
+                     SemIR::BindNameId::Invalid);
+    context.DiagnoseDuplicateName(conflict_id, it->second);
+  }
+}
+
 auto ImportLibraryFromCurrentPackage(Context& context,
                                      SemIR::TypeId namespace_type_id,
                                      Parse::ImportDirectiveId node_id,
@@ -249,21 +321,8 @@ auto ImportLibraryFromCurrentPackage(Context& context,
           context, namespace_type_id, copied_namespaces, ir_id, import_inst_id,
           import_namespace_inst->name_scope_id, enclosing_scope_id, name_id);
     } else {
-      // Leave a placeholder that the inst comes from the other IR.
-      auto bind_name_id = context.bind_names().Add(
-          {.name_id = name_id,
-           .enclosing_scope_id = enclosing_scope_id,
-           .bind_index = SemIR::CompileTimeBindIndex::Invalid});
-      auto target_id = AddImportRef(
-          context, {.ir_id = ir_id, .inst_id = import_inst_id}, bind_name_id);
-      auto [it, success] = context.name_scopes()
-                               .Get(enclosing_scope_id)
-                               .names.insert({name_id, target_id});
-      if (!success) {
-        // TODO: Figure out how best to handle when an export is added that's a
-        // conflict. Right now it diagnoses as a conflict around here.
-        context.DiagnoseDuplicateName(target_id, it->second);
-      }
+      AddImportRefOrMerge(context, ir_id, import_sem_ir, import_inst_id,
+                          enclosing_scope_id, name_id);
     }
   }
 

+ 62 - 159
toolchain/check/testdata/packages/no_prelude/export_mixed.carbon

@@ -68,30 +68,11 @@ import library "export_name_then_import";
 
 var c: C = {.x = ()};
 
-// --- fail_todo_use_both.carbon
+// --- use_both.carbon
 
 library "use_both" api;
 
 import library "export_import_then_name";
-// CHECK:STDERR: fail_todo_use_both.carbon:[[@LINE+19]]:1: In import.
-// CHECK:STDERR: import library "export_name_then_import";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: export_name.carbon:4:1: In import.
-// CHECK:STDERR: import library "base";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: base.carbon:4:1: ERROR: Duplicate name being declared in the same scope.
-// CHECK:STDERR: class C {
-// CHECK:STDERR: ^~~~~~~~~
-// CHECK:STDERR: fail_todo_use_both.carbon:[[@LINE-10]]:1: In import.
-// CHECK:STDERR: import library "export_import_then_name";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: export_import_then_name.carbon:4:1: In import.
-// CHECK:STDERR: import library "export_import";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: base.carbon:4:1: Name is previously declared here.
-// CHECK:STDERR: class C {
-// CHECK:STDERR: ^~~~~~~~~
-// CHECK:STDERR:
 import library "export_name_then_import";
 
 var c: C = {.x = ()};
@@ -101,101 +82,28 @@ var c: C = {.x = ()};
 library "fail_nonexport_use_both" api;
 
 import library "export_import_then_name";
-// CHECK:STDERR: fail_nonexport_use_both.carbon:[[@LINE+19]]:1: In import.
-// CHECK:STDERR: import library "export_name_then_import";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: export_name.carbon:4:1: In import.
-// CHECK:STDERR: import library "base";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: base.carbon:4:1: ERROR: Duplicate name being declared in the same scope.
-// CHECK:STDERR: class C {
-// CHECK:STDERR: ^~~~~~~~~
-// CHECK:STDERR: fail_nonexport_use_both.carbon:[[@LINE-10]]:1: In import.
-// CHECK:STDERR: import library "export_import_then_name";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: export_import_then_name.carbon:4:1: In import.
-// CHECK:STDERR: import library "export_import";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: base.carbon:4:1: Name is previously declared here.
-// CHECK:STDERR: class C {
-// CHECK:STDERR: ^~~~~~~~~
-// CHECK:STDERR:
 import library "export_name_then_import";
 
-// CHECK:STDERR: fail_nonexport_use_both.carbon:[[@LINE+4]]:8: ERROR: Name `D` not found.
+// CHECK:STDERR: fail_nonexport_use_both.carbon:[[@LINE+3]]:8: ERROR: Name `D` not found.
 // CHECK:STDERR: var d: D = {.y = ()};
 // CHECK:STDERR:        ^
-// CHECK:STDERR:
 var d: D = {.y = ()};
 
-// --- fail_todo_use_both_reversed.carbon
+// --- use_both_reversed.carbon
 
 library "use_both_reversed" api;
 
 import library "export_import_then_name";
-// CHECK:STDERR: fail_todo_use_both_reversed.carbon:[[@LINE+19]]:1: In import.
-// CHECK:STDERR: import library "export_name_then_import";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: export_name.carbon:4:1: In import.
-// CHECK:STDERR: import library "base";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: base.carbon:4:1: ERROR: Duplicate name being declared in the same scope.
-// CHECK:STDERR: class C {
-// CHECK:STDERR: ^~~~~~~~~
-// CHECK:STDERR: fail_todo_use_both_reversed.carbon:[[@LINE-10]]:1: In import.
-// CHECK:STDERR: import library "export_import_then_name";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: export_import_then_name.carbon:4:1: In import.
-// CHECK:STDERR: import library "export_import";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: base.carbon:4:1: Name is previously declared here.
-// CHECK:STDERR: class C {
-// CHECK:STDERR: ^~~~~~~~~
-// CHECK:STDERR:
 import library "export_name_then_import";
 
 var c: C = {.x = ()};
 
-// --- fail_todo_use_both_and_export_import.carbon
+// --- use_both_and_export_import.carbon
 
 library "use_both_and_export_import" api;
 
 import library "export_import_then_name";
-// CHECK:STDERR: fail_todo_use_both_and_export_import.carbon:[[@LINE+19]]:1: In import.
-// CHECK:STDERR: import library "export_name_then_import";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: export_name.carbon:4:1: In import.
-// CHECK:STDERR: import library "base";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: base.carbon:4:1: ERROR: Duplicate name being declared in the same scope.
-// CHECK:STDERR: class C {
-// CHECK:STDERR: ^~~~~~~~~
-// CHECK:STDERR: fail_todo_use_both_and_export_import.carbon:[[@LINE-10]]:1: In import.
-// CHECK:STDERR: import library "export_import_then_name";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: export_import_then_name.carbon:4:1: In import.
-// CHECK:STDERR: import library "export_import";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: base.carbon:4:1: Name is previously declared here.
-// CHECK:STDERR: class C {
-// CHECK:STDERR: ^~~~~~~~~
-// CHECK:STDERR:
 import library "export_name_then_import";
-// CHECK:STDERR: fail_todo_use_both_and_export_import.carbon:[[@LINE+15]]:1: In import.
-// CHECK:STDERR: import library "export_import";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: base.carbon:4:1: ERROR: Duplicate name being declared in the same scope.
-// CHECK:STDERR: class C {
-// CHECK:STDERR: ^~~~~~~~~
-// CHECK:STDERR: fail_todo_use_both_and_export_import.carbon:[[@LINE-27]]:1: In import.
-// CHECK:STDERR: import library "export_import_then_name";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: export_import_then_name.carbon:4:1: In import.
-// CHECK:STDERR: import library "export_import";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: base.carbon:4:1: Name is previously declared here.
-// CHECK:STDERR: class C {
-// CHECK:STDERR: ^~~~~~~~~
 import library "export_import";
 
 var c: C = {.x = ()};
@@ -400,7 +308,7 @@ var d: D = {.y = ()};
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: --- fail_todo_use_both.carbon
+// CHECK:STDOUT: --- use_both.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT:   %C: type = class_type @C [template]
@@ -417,9 +325,8 @@ var d: D = {.y = ()};
 // CHECK:STDOUT:     .c = %c
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %import_ref.1: type = import_ref ir1, inst+11, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.2 = import_ref ir3, inst+11, unloaded
-// CHECK:STDOUT:   %import_ref.3 = import_ref ir1, inst+10, unloaded
-// CHECK:STDOUT:   %import_ref.4 = import_ref ir1, inst+9, unloaded
+// CHECK:STDOUT:   %import_ref.2 = import_ref ir1, inst+10, unloaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref ir1, inst+9, unloaded
 // CHECK:STDOUT:   %C.ref: type = name_ref C, %import_ref.1 [template = constants.%C]
 // CHECK:STDOUT:   %c.var: ref C = var c
 // CHECK:STDOUT:   %c: ref C = bind_name c, %c.var
@@ -427,20 +334,20 @@ var d: D = {.y = ()};
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = file.%import_ref.3
-// CHECK:STDOUT:   .x = file.%import_ref.4
+// CHECK:STDOUT:   .Self = file.%import_ref.2
+// CHECK:STDOUT:   .x = file.%import_ref.3
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %.loc26_19.1: () = tuple_literal ()
-// CHECK:STDOUT:   %.loc26_20.1: {.x: ()} = struct_literal (%.loc26_19.1)
-// CHECK:STDOUT:   %.loc26_20.2: ref () = class_element_access file.%c.var, element0
-// CHECK:STDOUT:   %.loc26_19.2: init () = tuple_init () to %.loc26_20.2 [template = constants.%tuple]
-// CHECK:STDOUT:   %.loc26_20.3: init () = converted %.loc26_19.1, %.loc26_19.2 [template = constants.%tuple]
-// CHECK:STDOUT:   %.loc26_20.4: init C = class_init (%.loc26_20.3), file.%c.var [template = constants.%struct]
-// CHECK:STDOUT:   %.loc26_21: init C = converted %.loc26_20.1, %.loc26_20.4 [template = constants.%struct]
-// CHECK:STDOUT:   assign file.%c.var, %.loc26_21
+// CHECK:STDOUT:   %.loc7_19.1: () = tuple_literal ()
+// CHECK:STDOUT:   %.loc7_20.1: {.x: ()} = struct_literal (%.loc7_19.1)
+// CHECK:STDOUT:   %.loc7_20.2: ref () = class_element_access file.%c.var, element0
+// CHECK:STDOUT:   %.loc7_19.2: init () = tuple_init () to %.loc7_20.2 [template = constants.%tuple]
+// CHECK:STDOUT:   %.loc7_20.3: init () = converted %.loc7_19.1, %.loc7_19.2 [template = constants.%tuple]
+// CHECK:STDOUT:   %.loc7_20.4: init C = class_init (%.loc7_20.3), file.%c.var [template = constants.%struct]
+// CHECK:STDOUT:   %.loc7_21: init C = converted %.loc7_20.1, %.loc7_20.4 [template = constants.%struct]
+// CHECK:STDOUT:   assign file.%c.var, %.loc7_21
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -453,11 +360,10 @@ var d: D = {.y = ()};
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [template] {
-// CHECK:STDOUT:     .C = %import_ref.1
+// CHECK:STDOUT:     .C = %import_ref
 // CHECK:STDOUT:     .d = %d
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.1 = import_ref ir1, inst+11, unloaded
-// CHECK:STDOUT:   %import_ref.2 = import_ref ir3, inst+11, unloaded
+// CHECK:STDOUT:   %import_ref = import_ref ir1, inst+11, unloaded
 // CHECK:STDOUT:   %D.ref: <error> = name_ref D, <error> [template = <error>]
 // CHECK:STDOUT:   %d.var: ref <error> = var d
 // CHECK:STDOUT:   %d: ref <error> = bind_name d, %d.var
@@ -465,13 +371,13 @@ var d: D = {.y = ()};
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %.loc30_19: () = tuple_literal ()
-// CHECK:STDOUT:   %.loc30_20: {.y: ()} = struct_literal (%.loc30_19)
+// CHECK:STDOUT:   %.loc10_19: () = tuple_literal ()
+// CHECK:STDOUT:   %.loc10_20: {.y: ()} = struct_literal (%.loc10_19)
 // CHECK:STDOUT:   assign file.%d.var, <error>
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: --- fail_todo_use_both_reversed.carbon
+// CHECK:STDOUT: --- use_both_reversed.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT:   %C: type = class_type @C [template]
@@ -488,9 +394,8 @@ var d: D = {.y = ()};
 // CHECK:STDOUT:     .c = %c
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %import_ref.1: type = import_ref ir1, inst+11, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.2 = import_ref ir3, inst+11, unloaded
-// CHECK:STDOUT:   %import_ref.3 = import_ref ir1, inst+10, unloaded
-// CHECK:STDOUT:   %import_ref.4 = import_ref ir1, inst+9, unloaded
+// CHECK:STDOUT:   %import_ref.2 = import_ref ir1, inst+10, unloaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref ir1, inst+9, unloaded
 // CHECK:STDOUT:   %C.ref: type = name_ref C, %import_ref.1 [template = constants.%C]
 // CHECK:STDOUT:   %c.var: ref C = var c
 // CHECK:STDOUT:   %c: ref C = bind_name c, %c.var
@@ -498,24 +403,24 @@ var d: D = {.y = ()};
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = file.%import_ref.3
-// CHECK:STDOUT:   .x = file.%import_ref.4
+// CHECK:STDOUT:   .Self = file.%import_ref.2
+// CHECK:STDOUT:   .x = file.%import_ref.3
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %.loc26_19.1: () = tuple_literal ()
-// CHECK:STDOUT:   %.loc26_20.1: {.x: ()} = struct_literal (%.loc26_19.1)
-// CHECK:STDOUT:   %.loc26_20.2: ref () = class_element_access file.%c.var, element0
-// CHECK:STDOUT:   %.loc26_19.2: init () = tuple_init () to %.loc26_20.2 [template = constants.%tuple]
-// CHECK:STDOUT:   %.loc26_20.3: init () = converted %.loc26_19.1, %.loc26_19.2 [template = constants.%tuple]
-// CHECK:STDOUT:   %.loc26_20.4: init C = class_init (%.loc26_20.3), file.%c.var [template = constants.%struct]
-// CHECK:STDOUT:   %.loc26_21: init C = converted %.loc26_20.1, %.loc26_20.4 [template = constants.%struct]
-// CHECK:STDOUT:   assign file.%c.var, %.loc26_21
+// CHECK:STDOUT:   %.loc7_19.1: () = tuple_literal ()
+// CHECK:STDOUT:   %.loc7_20.1: {.x: ()} = struct_literal (%.loc7_19.1)
+// CHECK:STDOUT:   %.loc7_20.2: ref () = class_element_access file.%c.var, element0
+// CHECK:STDOUT:   %.loc7_19.2: init () = tuple_init () to %.loc7_20.2 [template = constants.%tuple]
+// CHECK:STDOUT:   %.loc7_20.3: init () = converted %.loc7_19.1, %.loc7_19.2 [template = constants.%tuple]
+// CHECK:STDOUT:   %.loc7_20.4: init C = class_init (%.loc7_20.3), file.%c.var [template = constants.%struct]
+// CHECK:STDOUT:   %.loc7_21: init C = converted %.loc7_20.1, %.loc7_20.4 [template = constants.%struct]
+// CHECK:STDOUT:   assign file.%c.var, %.loc7_21
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: --- fail_todo_use_both_and_export_import.carbon
+// CHECK:STDOUT: --- use_both_and_export_import.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT:   %C: type = class_type @C [template]
@@ -533,56 +438,54 @@ var d: D = {.y = ()};
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [template] {
 // CHECK:STDOUT:     .C = %import_ref.1
-// CHECK:STDOUT:     .D = %import_ref.4
+// CHECK:STDOUT:     .D = %import_ref.2
 // CHECK:STDOUT:     .c = %c
 // CHECK:STDOUT:     .d = %d
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %import_ref.1: type = import_ref ir1, inst+11, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.2 = import_ref ir3, inst+11, unloaded
-// CHECK:STDOUT:   %import_ref.3 = import_ref ir5, inst+1, unloaded
-// CHECK:STDOUT:   %import_ref.4: type = import_ref ir5, inst+11, loaded [template = constants.%D]
-// CHECK:STDOUT:   %import_ref.5 = import_ref ir1, inst+10, unloaded
-// CHECK:STDOUT:   %import_ref.6 = import_ref ir1, inst+9, unloaded
+// CHECK:STDOUT:   %import_ref.2: type = import_ref ir4, inst+11, loaded [template = constants.%D]
+// CHECK:STDOUT:   %import_ref.3 = import_ref ir1, inst+10, unloaded
+// CHECK:STDOUT:   %import_ref.4 = import_ref ir1, inst+9, unloaded
 // CHECK:STDOUT:   %C.ref: type = name_ref C, %import_ref.1 [template = constants.%C]
 // CHECK:STDOUT:   %c.var: ref C = var c
 // CHECK:STDOUT:   %c: ref C = bind_name c, %c.var
-// CHECK:STDOUT:   %import_ref.7 = import_ref ir5, inst+12, unloaded
-// CHECK:STDOUT:   %import_ref.8 = import_ref ir5, inst+16, unloaded
-// CHECK:STDOUT:   %D.ref: type = name_ref D, %import_ref.4 [template = constants.%D]
+// CHECK:STDOUT:   %import_ref.5 = import_ref ir4, inst+12, unloaded
+// CHECK:STDOUT:   %import_ref.6 = import_ref ir4, inst+16, unloaded
+// CHECK:STDOUT:   %D.ref: type = name_ref D, %import_ref.2 [template = constants.%D]
 // CHECK:STDOUT:   %d.var: ref D = var d
 // CHECK:STDOUT:   %d: ref D = bind_name d, %d.var
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = file.%import_ref.5
-// CHECK:STDOUT:   .x = file.%import_ref.6
+// CHECK:STDOUT:   .Self = file.%import_ref.3
+// CHECK:STDOUT:   .x = file.%import_ref.4
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @D {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = file.%import_ref.7
-// CHECK:STDOUT:   .y = file.%import_ref.8
+// CHECK:STDOUT:   .Self = file.%import_ref.5
+// CHECK:STDOUT:   .y = file.%import_ref.6
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %.loc42_19.1: () = tuple_literal ()
-// CHECK:STDOUT:   %.loc42_20.1: {.x: ()} = struct_literal (%.loc42_19.1)
-// CHECK:STDOUT:   %.loc42_20.2: ref () = class_element_access file.%c.var, element0
-// CHECK:STDOUT:   %.loc42_19.2: init () = tuple_init () to %.loc42_20.2 [template = constants.%tuple]
-// CHECK:STDOUT:   %.loc42_20.3: init () = converted %.loc42_19.1, %.loc42_19.2 [template = constants.%tuple]
-// CHECK:STDOUT:   %.loc42_20.4: init C = class_init (%.loc42_20.3), file.%c.var [template = constants.%struct.1]
-// CHECK:STDOUT:   %.loc42_21: init C = converted %.loc42_20.1, %.loc42_20.4 [template = constants.%struct.1]
-// CHECK:STDOUT:   assign file.%c.var, %.loc42_21
-// CHECK:STDOUT:   %.loc43_19.1: () = tuple_literal ()
-// CHECK:STDOUT:   %.loc43_20.1: {.y: ()} = struct_literal (%.loc43_19.1)
-// CHECK:STDOUT:   %.loc43_20.2: ref () = class_element_access file.%d.var, element0
-// CHECK:STDOUT:   %.loc43_19.2: init () = tuple_init () to %.loc43_20.2 [template = constants.%tuple]
-// CHECK:STDOUT:   %.loc43_20.3: init () = converted %.loc43_19.1, %.loc43_19.2 [template = constants.%tuple]
-// CHECK:STDOUT:   %.loc43_20.4: init D = class_init (%.loc43_20.3), file.%d.var [template = constants.%struct.2]
-// CHECK:STDOUT:   %.loc43_21: init D = converted %.loc43_20.1, %.loc43_20.4 [template = constants.%struct.2]
-// CHECK:STDOUT:   assign file.%d.var, %.loc43_21
+// CHECK:STDOUT:   %.loc8_19.1: () = tuple_literal ()
+// CHECK:STDOUT:   %.loc8_20.1: {.x: ()} = struct_literal (%.loc8_19.1)
+// CHECK:STDOUT:   %.loc8_20.2: ref () = class_element_access file.%c.var, element0
+// CHECK:STDOUT:   %.loc8_19.2: init () = tuple_init () to %.loc8_20.2 [template = constants.%tuple]
+// CHECK:STDOUT:   %.loc8_20.3: init () = converted %.loc8_19.1, %.loc8_19.2 [template = constants.%tuple]
+// CHECK:STDOUT:   %.loc8_20.4: init C = class_init (%.loc8_20.3), file.%c.var [template = constants.%struct.1]
+// CHECK:STDOUT:   %.loc8_21: init C = converted %.loc8_20.1, %.loc8_20.4 [template = constants.%struct.1]
+// CHECK:STDOUT:   assign file.%c.var, %.loc8_21
+// CHECK:STDOUT:   %.loc9_19.1: () = tuple_literal ()
+// CHECK:STDOUT:   %.loc9_20.1: {.y: ()} = struct_literal (%.loc9_19.1)
+// CHECK:STDOUT:   %.loc9_20.2: ref () = class_element_access file.%d.var, element0
+// CHECK:STDOUT:   %.loc9_19.2: init () = tuple_init () to %.loc9_20.2 [template = constants.%tuple]
+// CHECK:STDOUT:   %.loc9_20.3: init () = converted %.loc9_19.1, %.loc9_19.2 [template = constants.%tuple]
+// CHECK:STDOUT:   %.loc9_20.4: init D = class_init (%.loc9_20.3), file.%d.var [template = constants.%struct.2]
+// CHECK:STDOUT:   %.loc9_21: init D = converted %.loc9_20.1, %.loc9_20.4 [template = constants.%struct.2]
+// CHECK:STDOUT:   assign file.%d.var, %.loc9_21
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 66 - 154
toolchain/check/testdata/packages/no_prelude/export_name.carbon

@@ -125,85 +125,21 @@ import library "base";
 // CHECK:STDERR:
 export C.x;
 
-// --- fail_todo_import_both.carbon
+// --- import_both.carbon
 
 library "import_both" api;
 
 import library "base";
-// CHECK:STDERR: fail_todo_import_both.carbon:[[@LINE+32]]:1: In import.
-// CHECK:STDERR: import library "export";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: export.carbon:4:1: In import.
-// CHECK:STDERR: import library "base";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: base.carbon:4:1: ERROR: Duplicate name being declared in the same scope.
-// CHECK:STDERR: class C {
-// CHECK:STDERR: ^~~~~~~~~
-// CHECK:STDERR: fail_todo_import_both.carbon:[[@LINE-10]]:1: In import.
-// CHECK:STDERR: import library "base";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: base.carbon:4:1: Name is previously declared here.
-// CHECK:STDERR: class C {
-// CHECK:STDERR: ^~~~~~~~~
-// CHECK:STDERR:
-// CHECK:STDERR: fail_todo_import_both.carbon:[[@LINE+16]]:1: In import.
-// CHECK:STDERR: import library "export";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: export.carbon:4:1: In import.
-// CHECK:STDERR: import library "base";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: base.carbon:9:1: ERROR: Duplicate name being declared in the same scope.
-// CHECK:STDERR: class NS.NSC {
-// CHECK:STDERR: ^~~~~~~~~~~~~~
-// CHECK:STDERR: fail_todo_import_both.carbon:[[@LINE-26]]:1: In import.
-// CHECK:STDERR: import library "base";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: base.carbon:9:1: Name is previously declared here.
-// CHECK:STDERR: class NS.NSC {
-// CHECK:STDERR: ^~~~~~~~~~~~~~
-// CHECK:STDERR:
 import library "export";
 
 var c: C = {.x = ()};
 var nsc: NS.NSC = {.y = ()};
 
-// --- fail_todo_import_both_reversed.carbon
+// --- import_both_reversed.carbon
 
 library "import_both_reversed" api;
 
 import library "export";
-// CHECK:STDERR: fail_todo_import_both_reversed.carbon:[[@LINE+32]]:1: In import.
-// CHECK:STDERR: import library "base";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: base.carbon:4:1: ERROR: Duplicate name being declared in the same scope.
-// CHECK:STDERR: class C {
-// CHECK:STDERR: ^~~~~~~~~
-// CHECK:STDERR: fail_todo_import_both_reversed.carbon:[[@LINE-7]]:1: In import.
-// CHECK:STDERR: import library "export";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: export.carbon:4:1: In import.
-// CHECK:STDERR: import library "base";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: base.carbon:4:1: Name is previously declared here.
-// CHECK:STDERR: class C {
-// CHECK:STDERR: ^~~~~~~~~
-// CHECK:STDERR:
-// CHECK:STDERR: fail_todo_import_both_reversed.carbon:[[@LINE+16]]:1: In import.
-// CHECK:STDERR: import library "base";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: base.carbon:9:1: ERROR: Duplicate name being declared in the same scope.
-// CHECK:STDERR: class NS.NSC {
-// CHECK:STDERR: ^~~~~~~~~~~~~~
-// CHECK:STDERR: fail_todo_import_both_reversed.carbon:[[@LINE-23]]:1: In import.
-// CHECK:STDERR: import library "export";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: export.carbon:4:1: In import.
-// CHECK:STDERR: import library "base";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: base.carbon:9:1: Name is previously declared here.
-// CHECK:STDERR: class NS.NSC {
-// CHECK:STDERR: ^~~~~~~~~~~~~~
-// CHECK:STDERR:
 import library "base";
 
 var c: C = {.x = ()};
@@ -235,29 +171,10 @@ import library "base";
 export C;
 export C;
 
-// --- fail_todo_use_repeat_export.carbon
+// --- use_repeat_export.carbon
 
 library "use_repeat_export" api;
 
-// CHECK:STDERR: fail_todo_use_repeat_export.carbon:[[@LINE+19]]:1: In import.
-// CHECK:STDERR: import library "repeat_export";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: repeat_export.carbon:4:1: In import.
-// CHECK:STDERR: import library "base";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: base.carbon:4:1: ERROR: Duplicate name being declared in the same scope.
-// CHECK:STDERR: class C {
-// CHECK:STDERR: ^~~~~~~~~
-// CHECK:STDERR: fail_todo_use_repeat_export.carbon:[[@LINE+10]]:1: In import.
-// CHECK:STDERR: import library "repeat_export";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: repeat_export.carbon:4:1: In import.
-// CHECK:STDERR: import library "base";
-// CHECK:STDERR: ^~~~~~
-// CHECK:STDERR: base.carbon:4:1: Name is previously declared here.
-// CHECK:STDERR: class C {
-// CHECK:STDERR: ^~~~~~~~~
-// CHECK:STDERR:
 import library "repeat_export";
 
 var c: C = {.x = ()};
@@ -705,7 +622,7 @@ private export C;
 // CHECK:STDOUT:   .Self = file.%import_ref.5
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: --- fail_todo_import_both.carbon
+// CHECK:STDOUT: --- import_both.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT:   %C: type = class_type @C [template]
@@ -733,16 +650,14 @@ private export C;
 // CHECK:STDOUT:     .NSC = %import_ref.3
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %import_ref.3: type = import_ref ir1, inst+12, loaded [template = constants.%NSC]
-// CHECK:STDOUT:   %import_ref.4 = import_ref ir2, inst+13, unloaded
-// CHECK:STDOUT:   %import_ref.5 = import_ref ir2, inst+21, unloaded
-// CHECK:STDOUT:   %import_ref.6 = import_ref ir1, inst+7, unloaded
-// CHECK:STDOUT:   %import_ref.7 = import_ref ir1, inst+2, unloaded
+// CHECK:STDOUT:   %import_ref.4 = import_ref ir1, inst+7, unloaded
+// CHECK:STDOUT:   %import_ref.5 = import_ref ir1, inst+2, unloaded
 // CHECK:STDOUT:   %C.ref: type = name_ref C, %import_ref.1 [template = constants.%C]
 // CHECK:STDOUT:   %c.var: ref C = var c
 // CHECK:STDOUT:   %c: ref C = bind_name c, %c.var
 // CHECK:STDOUT:   %NS.ref: <namespace> = name_ref NS, %NS [template = %NS]
-// CHECK:STDOUT:   %import_ref.8 = import_ref ir1, inst+13, unloaded
-// CHECK:STDOUT:   %import_ref.9 = import_ref ir1, inst+17, unloaded
+// CHECK:STDOUT:   %import_ref.6 = import_ref ir1, inst+13, unloaded
+// CHECK:STDOUT:   %import_ref.7 = import_ref ir1, inst+17, unloaded
 // CHECK:STDOUT:   %NSC.ref: type = name_ref NSC, %import_ref.3 [template = constants.%NSC]
 // CHECK:STDOUT:   %nsc.var: ref NSC = var nsc
 // CHECK:STDOUT:   %nsc: ref NSC = bind_name nsc, %nsc.var
@@ -750,38 +665,38 @@ private export C;
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .x = file.%import_ref.6
-// CHECK:STDOUT:   .Self = file.%import_ref.7
+// CHECK:STDOUT:   .x = file.%import_ref.4
+// CHECK:STDOUT:   .Self = file.%import_ref.5
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @NSC {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = file.%import_ref.8
-// CHECK:STDOUT:   .y = file.%import_ref.9
+// CHECK:STDOUT:   .Self = file.%import_ref.6
+// CHECK:STDOUT:   .y = file.%import_ref.7
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %.loc39_19.1: () = tuple_literal ()
-// CHECK:STDOUT:   %.loc39_20.1: {.x: ()} = struct_literal (%.loc39_19.1)
-// CHECK:STDOUT:   %.loc39_20.2: ref () = class_element_access file.%c.var, element0
-// CHECK:STDOUT:   %.loc39_19.2: init () = tuple_init () to %.loc39_20.2 [template = constants.%tuple]
-// CHECK:STDOUT:   %.loc39_20.3: init () = converted %.loc39_19.1, %.loc39_19.2 [template = constants.%tuple]
-// CHECK:STDOUT:   %.loc39_20.4: init C = class_init (%.loc39_20.3), file.%c.var [template = constants.%struct.1]
-// CHECK:STDOUT:   %.loc39_21: init C = converted %.loc39_20.1, %.loc39_20.4 [template = constants.%struct.1]
-// CHECK:STDOUT:   assign file.%c.var, %.loc39_21
-// CHECK:STDOUT:   %.loc40_26.1: () = tuple_literal ()
-// CHECK:STDOUT:   %.loc40_27.1: {.y: ()} = struct_literal (%.loc40_26.1)
-// CHECK:STDOUT:   %.loc40_27.2: ref () = class_element_access file.%nsc.var, element0
-// CHECK:STDOUT:   %.loc40_26.2: init () = tuple_init () to %.loc40_27.2 [template = constants.%tuple]
-// CHECK:STDOUT:   %.loc40_27.3: init () = converted %.loc40_26.1, %.loc40_26.2 [template = constants.%tuple]
-// CHECK:STDOUT:   %.loc40_27.4: init NSC = class_init (%.loc40_27.3), file.%nsc.var [template = constants.%struct.2]
-// CHECK:STDOUT:   %.loc40_28: init NSC = converted %.loc40_27.1, %.loc40_27.4 [template = constants.%struct.2]
-// CHECK:STDOUT:   assign file.%nsc.var, %.loc40_28
+// CHECK:STDOUT:   %.loc7_19.1: () = tuple_literal ()
+// CHECK:STDOUT:   %.loc7_20.1: {.x: ()} = struct_literal (%.loc7_19.1)
+// CHECK:STDOUT:   %.loc7_20.2: ref () = class_element_access file.%c.var, element0
+// CHECK:STDOUT:   %.loc7_19.2: init () = tuple_init () to %.loc7_20.2 [template = constants.%tuple]
+// CHECK:STDOUT:   %.loc7_20.3: init () = converted %.loc7_19.1, %.loc7_19.2 [template = constants.%tuple]
+// CHECK:STDOUT:   %.loc7_20.4: init C = class_init (%.loc7_20.3), file.%c.var [template = constants.%struct.1]
+// CHECK:STDOUT:   %.loc7_21: init C = converted %.loc7_20.1, %.loc7_20.4 [template = constants.%struct.1]
+// CHECK:STDOUT:   assign file.%c.var, %.loc7_21
+// CHECK:STDOUT:   %.loc8_26.1: () = tuple_literal ()
+// CHECK:STDOUT:   %.loc8_27.1: {.y: ()} = struct_literal (%.loc8_26.1)
+// CHECK:STDOUT:   %.loc8_27.2: ref () = class_element_access file.%nsc.var, element0
+// CHECK:STDOUT:   %.loc8_26.2: init () = tuple_init () to %.loc8_27.2 [template = constants.%tuple]
+// CHECK:STDOUT:   %.loc8_27.3: init () = converted %.loc8_26.1, %.loc8_26.2 [template = constants.%tuple]
+// CHECK:STDOUT:   %.loc8_27.4: init NSC = class_init (%.loc8_27.3), file.%nsc.var [template = constants.%struct.2]
+// CHECK:STDOUT:   %.loc8_28: init NSC = converted %.loc8_27.1, %.loc8_27.4 [template = constants.%struct.2]
+// CHECK:STDOUT:   assign file.%nsc.var, %.loc8_28
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: --- fail_todo_import_both_reversed.carbon
+// CHECK:STDOUT: --- import_both_reversed.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT:   %C: type = class_type @C [template]
@@ -809,16 +724,14 @@ private export C;
 // CHECK:STDOUT:     .NSC = %import_ref.3
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %import_ref.3: type = import_ref ir1, inst+21, loaded [template = constants.%NSC]
-// CHECK:STDOUT:   %import_ref.4 = import_ref ir2, inst+1, unloaded
-// CHECK:STDOUT:   %import_ref.5 = import_ref ir2, inst+12, unloaded
-// CHECK:STDOUT:   %import_ref.6 = import_ref ir1, inst+12, unloaded
-// CHECK:STDOUT:   %import_ref.7 = import_ref ir1, inst+11, unloaded
+// CHECK:STDOUT:   %import_ref.4 = import_ref ir1, inst+12, unloaded
+// CHECK:STDOUT:   %import_ref.5 = import_ref ir1, inst+11, unloaded
 // CHECK:STDOUT:   %C.ref: type = name_ref C, %import_ref.1 [template = constants.%C]
 // CHECK:STDOUT:   %c.var: ref C = var c
 // CHECK:STDOUT:   %c: ref C = bind_name c, %c.var
 // CHECK:STDOUT:   %NS.ref: <namespace> = name_ref NS, %NS [template = %NS]
-// CHECK:STDOUT:   %import_ref.8 = import_ref ir1, inst+20, unloaded
-// CHECK:STDOUT:   %import_ref.9 = import_ref ir1, inst+19, unloaded
+// CHECK:STDOUT:   %import_ref.6 = import_ref ir1, inst+20, unloaded
+// CHECK:STDOUT:   %import_ref.7 = import_ref ir1, inst+19, unloaded
 // CHECK:STDOUT:   %NSC.ref: type = name_ref NSC, %import_ref.3 [template = constants.%NSC]
 // CHECK:STDOUT:   %nsc.var: ref NSC = var nsc
 // CHECK:STDOUT:   %nsc: ref NSC = bind_name nsc, %nsc.var
@@ -826,34 +739,34 @@ private export C;
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = file.%import_ref.6
-// CHECK:STDOUT:   .x = file.%import_ref.7
+// CHECK:STDOUT:   .Self = file.%import_ref.4
+// CHECK:STDOUT:   .x = file.%import_ref.5
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @NSC {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .y = file.%import_ref.8
-// CHECK:STDOUT:   .Self = file.%import_ref.9
+// CHECK:STDOUT:   .y = file.%import_ref.6
+// CHECK:STDOUT:   .Self = file.%import_ref.7
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %.loc39_19.1: () = tuple_literal ()
-// CHECK:STDOUT:   %.loc39_20.1: {.x: ()} = struct_literal (%.loc39_19.1)
-// CHECK:STDOUT:   %.loc39_20.2: ref () = class_element_access file.%c.var, element0
-// CHECK:STDOUT:   %.loc39_19.2: init () = tuple_init () to %.loc39_20.2 [template = constants.%tuple]
-// CHECK:STDOUT:   %.loc39_20.3: init () = converted %.loc39_19.1, %.loc39_19.2 [template = constants.%tuple]
-// CHECK:STDOUT:   %.loc39_20.4: init C = class_init (%.loc39_20.3), file.%c.var [template = constants.%struct.1]
-// CHECK:STDOUT:   %.loc39_21: init C = converted %.loc39_20.1, %.loc39_20.4 [template = constants.%struct.1]
-// CHECK:STDOUT:   assign file.%c.var, %.loc39_21
-// CHECK:STDOUT:   %.loc40_26.1: () = tuple_literal ()
-// CHECK:STDOUT:   %.loc40_27.1: {.y: ()} = struct_literal (%.loc40_26.1)
-// CHECK:STDOUT:   %.loc40_27.2: ref () = class_element_access file.%nsc.var, element0
-// CHECK:STDOUT:   %.loc40_26.2: init () = tuple_init () to %.loc40_27.2 [template = constants.%tuple]
-// CHECK:STDOUT:   %.loc40_27.3: init () = converted %.loc40_26.1, %.loc40_26.2 [template = constants.%tuple]
-// CHECK:STDOUT:   %.loc40_27.4: init NSC = class_init (%.loc40_27.3), file.%nsc.var [template = constants.%struct.2]
-// CHECK:STDOUT:   %.loc40_28: init NSC = converted %.loc40_27.1, %.loc40_27.4 [template = constants.%struct.2]
-// CHECK:STDOUT:   assign file.%nsc.var, %.loc40_28
+// CHECK:STDOUT:   %.loc7_19.1: () = tuple_literal ()
+// CHECK:STDOUT:   %.loc7_20.1: {.x: ()} = struct_literal (%.loc7_19.1)
+// CHECK:STDOUT:   %.loc7_20.2: ref () = class_element_access file.%c.var, element0
+// CHECK:STDOUT:   %.loc7_19.2: init () = tuple_init () to %.loc7_20.2 [template = constants.%tuple]
+// CHECK:STDOUT:   %.loc7_20.3: init () = converted %.loc7_19.1, %.loc7_19.2 [template = constants.%tuple]
+// CHECK:STDOUT:   %.loc7_20.4: init C = class_init (%.loc7_20.3), file.%c.var [template = constants.%struct.1]
+// CHECK:STDOUT:   %.loc7_21: init C = converted %.loc7_20.1, %.loc7_20.4 [template = constants.%struct.1]
+// CHECK:STDOUT:   assign file.%c.var, %.loc7_21
+// CHECK:STDOUT:   %.loc8_26.1: () = tuple_literal ()
+// CHECK:STDOUT:   %.loc8_27.1: {.y: ()} = struct_literal (%.loc8_26.1)
+// CHECK:STDOUT:   %.loc8_27.2: ref () = class_element_access file.%nsc.var, element0
+// CHECK:STDOUT:   %.loc8_26.2: init () = tuple_init () to %.loc8_27.2 [template = constants.%tuple]
+// CHECK:STDOUT:   %.loc8_27.3: init () = converted %.loc8_26.1, %.loc8_26.2 [template = constants.%tuple]
+// CHECK:STDOUT:   %.loc8_27.4: init NSC = class_init (%.loc8_27.3), file.%nsc.var [template = constants.%struct.2]
+// CHECK:STDOUT:   %.loc8_28: init NSC = converted %.loc8_27.1, %.loc8_27.4 [template = constants.%struct.2]
+// CHECK:STDOUT:   assign file.%nsc.var, %.loc8_28
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -901,7 +814,7 @@ private export C;
 // CHECK:STDOUT:   .Self = file.%import_ref.5
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: --- fail_todo_use_repeat_export.carbon
+// CHECK:STDOUT: --- use_repeat_export.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT:   %C: type = class_type @C [template]
@@ -918,9 +831,8 @@ private export C;
 // CHECK:STDOUT:     .c = %c
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %import_ref.1: type = import_ref ir1, inst+13, loaded [template = constants.%C]
-// CHECK:STDOUT:   %import_ref.2 = import_ref ir1, inst+14, unloaded
-// CHECK:STDOUT:   %import_ref.3 = import_ref ir1, inst+12, unloaded
-// CHECK:STDOUT:   %import_ref.4 = import_ref ir1, inst+11, unloaded
+// CHECK:STDOUT:   %import_ref.2 = import_ref ir1, inst+12, unloaded
+// CHECK:STDOUT:   %import_ref.3 = import_ref ir1, inst+11, unloaded
 // CHECK:STDOUT:   %C.ref: type = name_ref C, %import_ref.1 [template = constants.%C]
 // CHECK:STDOUT:   %c.var: ref C = var c
 // CHECK:STDOUT:   %c: ref C = bind_name c, %c.var
@@ -928,20 +840,20 @@ private export C;
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = file.%import_ref.3
-// CHECK:STDOUT:   .x = file.%import_ref.4
+// CHECK:STDOUT:   .Self = file.%import_ref.2
+// CHECK:STDOUT:   .x = file.%import_ref.3
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %.loc25_19.1: () = tuple_literal ()
-// CHECK:STDOUT:   %.loc25_20.1: {.x: ()} = struct_literal (%.loc25_19.1)
-// CHECK:STDOUT:   %.loc25_20.2: ref () = class_element_access file.%c.var, element0
-// CHECK:STDOUT:   %.loc25_19.2: init () = tuple_init () to %.loc25_20.2 [template = constants.%tuple]
-// CHECK:STDOUT:   %.loc25_20.3: init () = converted %.loc25_19.1, %.loc25_19.2 [template = constants.%tuple]
-// CHECK:STDOUT:   %.loc25_20.4: init C = class_init (%.loc25_20.3), file.%c.var [template = constants.%struct]
-// CHECK:STDOUT:   %.loc25_21: init C = converted %.loc25_20.1, %.loc25_20.4 [template = constants.%struct]
-// CHECK:STDOUT:   assign file.%c.var, %.loc25_21
+// CHECK:STDOUT:   %.loc6_19.1: () = tuple_literal ()
+// CHECK:STDOUT:   %.loc6_20.1: {.x: ()} = struct_literal (%.loc6_19.1)
+// CHECK:STDOUT:   %.loc6_20.2: ref () = class_element_access file.%c.var, element0
+// CHECK:STDOUT:   %.loc6_19.2: init () = tuple_init () to %.loc6_20.2 [template = constants.%tuple]
+// CHECK:STDOUT:   %.loc6_20.3: init () = converted %.loc6_19.1, %.loc6_19.2 [template = constants.%tuple]
+// CHECK:STDOUT:   %.loc6_20.4: init C = class_init (%.loc6_20.3), file.%c.var [template = constants.%struct]
+// CHECK:STDOUT:   %.loc6_21: init C = converted %.loc6_20.1, %.loc6_20.4 [template = constants.%struct]
+// CHECK:STDOUT:   assign file.%c.var, %.loc6_21
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 4 - 0
toolchain/sem_ir/import_ir.h

@@ -30,6 +30,10 @@ struct ImportIRInst : public Printable<ImportIRInst> {
     out << ir_id << ":" << inst_id;
   }
 
+  auto operator==(const ImportIRInst& rhs) const -> bool {
+    return ir_id == rhs.ir_id && inst_id == rhs.inst_id;
+  }
+
   ImportIRId ir_id;
   InstId inst_id;
 };