Handle merging of conflicting 'export name' cross-package imports. (#3973)

This commit is contained in:
Jon Ross-Perkins
2024-05-22 22:35:48 +00:00
committed by GitHub
parent 41a84222c2
commit d4025dc6c4
5 changed files with 267 additions and 170 deletions
+19 -11
View File
@@ -23,6 +23,7 @@
#include "toolchain/sem_ir/builtin_kind.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/inst_kind.h"
#include "toolchain/sem_ir/typed_insts.h"
@@ -300,7 +301,8 @@ static auto LookupInImportIRScopes(Context& context, SemIRLoc loc,
});
auto result_id = SemIR::InstId::Invalid;
auto bind_name_id = SemIR::BindNameId::Invalid;
std::optional<SemIR::ImportIRInst> canonical_result_inst;
for (auto [import_ir_id, import_scope_id] : scope.import_ir_scopes) {
auto& import_ir = context.import_irs().Get(import_ir_id);
@@ -330,19 +332,25 @@ static auto LookupInImportIRScopes(Context& context, SemIRLoc loc,
continue;
}
if (!bind_name_id.is_valid()) {
bind_name_id = context.bind_names().Add(
if (result_id.is_valid()) {
// On a conflict, we verify the canonical instruction is the same.
if (!canonical_result_inst) {
canonical_result_inst =
GetCanonicalImportIRInst(context, &context.sem_ir(), result_id);
}
VerifySameCanonicalImportIRInst(context, result_id,
*canonical_result_inst, import_ir_id,
import_ir.sem_ir, it->second);
} else {
// Add the first result found.
auto bind_name_id = context.bind_names().Add(
{.name_id = name_id,
.enclosing_scope_id = scope_id,
.bind_index = SemIR::CompileTimeBindIndex::Invalid});
}
auto import_inst_id = AddImportRef(
context, {.ir_id = import_ir_id, .inst_id = it->second}, bind_name_id);
if (result_id.is_valid()) {
context.DiagnoseDuplicateName(import_inst_id, result_id);
} else {
LoadImportRef(context, import_inst_id);
result_id = import_inst_id;
result_id =
AddImportRef(context, {.ir_id = import_ir_id, .inst_id = it->second},
bind_name_id);
LoadImportRef(context, result_id);
}
}
+2 -48
View File
@@ -217,43 +217,6 @@ 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::ExportDecl 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,
@@ -275,17 +238,8 @@ static auto AddImportRefOrMerge(Context& context, SemIR::ImportIRId ir_id,
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);
}
VerifySameCanonicalImportIRInst(context, it->second, prev_ir_inst, ir_id,
&import_sem_ir, import_inst_id);
}
auto ImportLibrariesFromCurrentPackage(
+50
View File
@@ -72,6 +72,56 @@ auto AddImportRef(Context& context, SemIR::ImportIRInst import_ir_inst,
return import_ref_id;
}
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::ExportDecl 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};
}
}
}
}
auto VerifySameCanonicalImportIRInst(Context& context, SemIR::InstId prev_id,
SemIR::ImportIRInst prev_import_ir_inst,
SemIR::ImportIRId new_ir_id,
const SemIR::File* new_import_ir,
SemIR::InstId new_inst_id) -> void {
auto new_import_ir_inst =
GetCanonicalImportIRInst(context, new_import_ir, new_inst_id);
if (new_import_ir_inst == prev_import_ir_inst) {
return;
}
auto conflict_id =
AddImportRef(context, {.ir_id = new_ir_id, .inst_id = new_inst_id},
SemIR::BindNameId::Invalid);
context.DiagnoseDuplicateName(conflict_id, prev_id);
}
// Resolves an instruction from an imported IR into a constant referring to the
// current IR.
//
+14
View File
@@ -24,6 +24,20 @@ auto AddImportIR(Context& context, SemIR::ImportIR import_ir)
auto AddImportRef(Context& context, SemIR::ImportIRInst import_ir_inst,
SemIR::BindNameId bind_name_id) -> SemIR::InstId;
// Returns the canonical IR inst for an entity. Returns an invalid ir_id for the
// current IR.
auto GetCanonicalImportIRInst(Context& context, const SemIR::File* cursor_ir,
SemIR::InstId cursor_inst_id)
-> SemIR::ImportIRInst;
// Verifies a new instruction is the same as a previous instruction.
// prev_import_ir_inst should come from GetCanonicalImportIRInst.
auto VerifySameCanonicalImportIRInst(Context& context, SemIR::InstId prev_id,
SemIR::ImportIRInst prev_import_ir_inst,
SemIR::ImportIRId new_ir_id,
const SemIR::File* new_import_ir,
SemIR::InstId new_inst_id) -> void;
// If the passed in instruction ID is an ImportRefUnloaded, turns it into an
// ImportRefLoaded for use.
auto LoadImportRef(Context& context, SemIR::InstId inst_id) -> void;
@@ -16,6 +16,12 @@ class C {
var x: ();
};
// --- conflict.carbon
package Other library "conflict";
fn C() {}
// --- export_import.carbon
package Other library "export_import";
@@ -95,35 +101,13 @@ import Other library "export_name";
var c: Other.C = {.x = ()};
// --- fail_todo_use_export_name_with_copy.carbon
// --- use_export_name_with_copy.carbon
library "use_export_name_with_copy";
import Other library "export_name";
// CHECK:STDERR: fail_todo_use_export_name_with_copy.carbon:[[@LINE+18]]:1: In import.
// CHECK:STDERR: import Other library "export_name_copy";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: export_name_copy.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_export_name_with_copy.carbon:[[@LINE-10]]:1: In import.
// CHECK:STDERR: import Other library "export_name";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: export_name.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: ^~~~~~~~~
import Other library "export_name_copy";
// CHECK:STDERR: fail_todo_use_export_name_with_copy.carbon:[[@LINE+4]]:8: In name lookup for `C`.
// CHECK:STDERR: var c: Other.C = {.x = ()};
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
var c: Other.C = {.x = ()};
// --- use_export_name_indirect.carbon
@@ -134,84 +118,85 @@ import Other library "export_name_indirect";
var c: Other.C = {.x = ()};
// --- fail_todo_use_export_all.carbon
// --- use_export_all.carbon
library "use_export_all";
// CHECK:STDERR: fail_todo_use_export_all.carbon:[[@LINE+6]]:1: In import.
// CHECK:STDERR: import Other 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: ^~~~~~~~~
import Other library "export_import";
// CHECK:STDERR: fail_todo_use_export_all.carbon:[[@LINE+9]]:1: In import.
// CHECK:STDERR: import Other library "export_name";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: export_name.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: ^~~~~~~~~
import Other library "export_name";
import Other library "export_import_copy";
import Other library "export_name_copy";
import Other library "export_import_indirect";
import Other library "export_name_indirect";
// CHECK:STDERR: fail_todo_use_export_all.carbon:[[@LINE+50]]:8: In name lookup for `C`.
// CHECK:STDERR: var c: Other.C = {.x = ()};
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_todo_use_export_all.carbon:[[@LINE-8]]:1: In import.
// CHECK:STDERR: import Other library "export_name_copy";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: export_name_copy.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_export_all.carbon:[[@LINE-19]]:1: In import.
// CHECK:STDERR: import Other library "export_name";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: export_name.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: fail_todo_use_export_all.carbon:[[@LINE+28]]:8: In name lookup for `C`.
// CHECK:STDERR: var c: Other.C = {.x = ()};
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_todo_use_export_all.carbon:[[@LINE-28]]:1: In import.
// CHECK:STDERR: import Other library "export_name_indirect";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: export_name_indirect.carbon:4:1: In import.
// CHECK:STDERR: import library "export_name";
// 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_export_all.carbon:[[@LINE-44]]:1: In import.
// CHECK:STDERR: import Other library "export_name";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: export_name.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: fail_todo_use_export_all.carbon:[[@LINE+3]]:8: In name lookup for `C`.
// CHECK:STDERR: var c: Other.C = {.x = ()};
// CHECK:STDERR: ^~~~~~~
var c: Other.C = {.x = ()};
// --- unused_conflict_on_export_import.carbon
library "unused_conflict_on_export_import";
import Other library "export_import";
import Other library "conflict";
// --- unused_conflict_on_export_name.carbon
library "unused_conflict_on_export_name";
import Other library "export_name";
import Other library "conflict";
// --- fail_conflict_on_export_import.carbon
library "fail_conflict_on_export_import";
// CHECK:STDERR: fail_conflict_on_export_import.carbon:[[@LINE+6]]:1: In import.
// CHECK:STDERR: import Other 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: ^~~~~~~~~
import Other library "export_import";
// CHECK:STDERR: fail_conflict_on_export_import.carbon:[[@LINE+6]]:1: In import.
// CHECK:STDERR: import Other library "conflict";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: conflict.carbon:4:1: Name is previously declared here.
// CHECK:STDERR: fn C() {}
// CHECK:STDERR: ^~~~~~~~
import Other library "conflict";
// CHECK:STDERR: fail_conflict_on_export_import.carbon:[[@LINE+4]]:11: In name lookup for `C`.
// CHECK:STDERR: alias C = Other.C;
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
alias C = Other.C;
// --- fail_conflict_on_export_name.carbon
library "fail_conflict_on_export_name";
import Other library "export_name";
// CHECK:STDERR: fail_conflict_on_export_name.carbon:[[@LINE+15]]:1: In import.
// CHECK:STDERR: import Other library "conflict";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: conflict.carbon:4:1: ERROR: Duplicate name being declared in the same scope.
// CHECK:STDERR: fn C() {}
// CHECK:STDERR: ^~~~~~~~
// CHECK:STDERR: fail_conflict_on_export_name.carbon:[[@LINE-7]]:1: In import.
// CHECK:STDERR: import Other library "export_name";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: export_name.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: ^~~~~~~~~
import Other library "conflict";
// CHECK:STDERR: fail_conflict_on_export_name.carbon:[[@LINE+3]]:11: In name lookup for `C`.
// CHECK:STDERR: alias C = Other.C;
// CHECK:STDERR: ^~~~~~~
alias C = Other.C;
// CHECK:STDOUT: --- base.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
@@ -238,6 +223,26 @@ var c: Other.C = {.x = ()};
// CHECK:STDOUT: .x = %.loc5_8
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- conflict.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = fn_type @C [template]
// CHECK:STDOUT: %.1: type = tuple_type () [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: }
// CHECK:STDOUT: %C.decl: C = fn_decl @C [template = constants.%struct] {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @C() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- export_import.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -517,7 +522,7 @@ var c: Other.C = {.x = ()};
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_use_export_name_with_copy.carbon
// CHECK:STDOUT: --- use_export_name_with_copy.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [template]
@@ -538,7 +543,6 @@ var c: Other.C = {.x = ()};
// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+10, loaded [template = constants.%C]
// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+8, unloaded
// CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+9, unloaded
// CHECK:STDOUT: %import_ref.4 = import_ref ir2, inst+10, 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
@@ -552,14 +556,14 @@ var c: Other.C = {.x = ()};
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc29_25.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc29_26.1: {.x: ()} = struct_literal (%.loc29_25.1)
// CHECK:STDOUT: %.loc29_26.2: ref () = class_element_access file.%c.var, element0
// CHECK:STDOUT: %.loc29_25.2: init () = tuple_init () to %.loc29_26.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc29_26.3: init () = converted %.loc29_25.1, %.loc29_25.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc29_26.4: init C = class_init (%.loc29_26.3), file.%c.var [template = constants.%struct]
// CHECK:STDOUT: %.loc29_27: init C = converted %.loc29_26.1, %.loc29_26.4 [template = constants.%struct]
// CHECK:STDOUT: assign file.%c.var, %.loc29_27
// CHECK:STDOUT: %.loc7_25.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc7_26.1: {.x: ()} = struct_literal (%.loc7_25.1)
// CHECK:STDOUT: %.loc7_26.2: ref () = class_element_access file.%c.var, element0
// CHECK:STDOUT: %.loc7_25.2: init () = tuple_init () to %.loc7_26.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc7_26.3: init () = converted %.loc7_25.1, %.loc7_25.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc7_26.4: init C = class_init (%.loc7_26.3), file.%c.var [template = constants.%struct]
// CHECK:STDOUT: %.loc7_27: init C = converted %.loc7_26.1, %.loc7_26.4 [template = constants.%struct]
// CHECK:STDOUT: assign file.%c.var, %.loc7_27
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -608,7 +612,7 @@ var c: Other.C = {.x = ()};
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_use_export_all.carbon
// CHECK:STDOUT: --- use_export_all.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [template]
@@ -629,9 +633,6 @@ var c: Other.C = {.x = ()};
// CHECK:STDOUT: %import_ref.1: type = import_ref ir2, inst+10, loaded [template = constants.%C]
// CHECK:STDOUT: %import_ref.2 = import_ref ir2, inst+8, unloaded
// CHECK:STDOUT: %import_ref.3 = import_ref ir2, inst+9, unloaded
// CHECK:STDOUT: %import_ref.4 = import_ref ir4, inst+10, unloaded
// CHECK:STDOUT: %import_ref.5 = import_ref ir6, inst+10, unloaded
// CHECK:STDOUT: %import_ref.6 = import_ref ir7, inst+1, 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
@@ -645,14 +646,84 @@ var c: Other.C = {.x = ()};
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc76_25.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc76_26.1: {.x: ()} = struct_literal (%.loc76_25.1)
// CHECK:STDOUT: %.loc76_26.2: ref () = class_element_access file.%c.var, element0
// CHECK:STDOUT: %.loc76_25.2: init () = tuple_init () to %.loc76_26.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc76_26.3: init () = converted %.loc76_25.1, %.loc76_25.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc76_26.4: init C = class_init (%.loc76_26.3), file.%c.var [template = constants.%struct]
// CHECK:STDOUT: %.loc76_27: init C = converted %.loc76_26.1, %.loc76_26.4 [template = constants.%struct]
// CHECK:STDOUT: assign file.%c.var, %.loc76_27
// CHECK:STDOUT: %.loc11_25.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc11_26.1: {.x: ()} = struct_literal (%.loc11_25.1)
// CHECK:STDOUT: %.loc11_26.2: ref () = class_element_access file.%c.var, element0
// CHECK:STDOUT: %.loc11_25.2: init () = tuple_init () to %.loc11_26.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc11_26.3: init () = converted %.loc11_25.1, %.loc11_25.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc11_26.4: init C = class_init (%.loc11_26.3), file.%c.var [template = constants.%struct]
// CHECK:STDOUT: %.loc11_27: init C = converted %.loc11_26.1, %.loc11_26.4 [template = constants.%struct]
// CHECK:STDOUT: assign file.%c.var, %.loc11_27
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- unused_conflict_on_export_import.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Other = %Other
// CHECK:STDOUT: }
// CHECK:STDOUT: %Other: <namespace> = namespace [template] {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- unused_conflict_on_export_name.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Other = %Other
// CHECK:STDOUT: }
// CHECK:STDOUT: %Other: <namespace> = namespace [template] {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_conflict_on_export_import.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = fn_type @C [template]
// CHECK:STDOUT: %.1: type = tuple_type () [template]
// CHECK:STDOUT: %struct: C = struct_value () [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Other = %Other
// CHECK:STDOUT: .C = %C
// CHECK:STDOUT: }
// CHECK:STDOUT: %Other: <namespace> = namespace [template] {}
// CHECK:STDOUT: %Other.ref: <namespace> = name_ref Other, %Other [template = %Other]
// CHECK:STDOUT: %import_ref.1: C = import_ref ir2, inst+1, loaded [template = constants.%struct]
// CHECK:STDOUT: %import_ref.2 = import_ref ir3, inst+1, unloaded
// CHECK:STDOUT: %C.ref: C = name_ref C, %import_ref.1 [template = constants.%struct]
// CHECK:STDOUT: %C: C = bind_alias C, %import_ref.1 [template = constants.%struct]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @C();
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_conflict_on_export_name.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [template]
// CHECK:STDOUT: %.1: type = tuple_type () [template]
// CHECK:STDOUT: %.2: type = struct_type {.x: ()} [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Other = %Other
// CHECK:STDOUT: .C = %C
// CHECK:STDOUT: }
// CHECK:STDOUT: %Other: <namespace> = namespace [template] {}
// CHECK:STDOUT: %Other.ref: <namespace> = name_ref Other, %Other [template = %Other]
// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+10, loaded [template = constants.%C]
// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+8, unloaded
// CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+9, unloaded
// CHECK:STDOUT: %import_ref.4 = import_ref ir2, inst+1, unloaded
// CHECK:STDOUT: %C.ref: type = name_ref C, %import_ref.1 [template = constants.%C]
// CHECK:STDOUT: %C: type = bind_alias C, %import_ref.1 [template = constants.%C]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = file.%import_ref.2
// CHECK:STDOUT: .x = file.%import_ref.3
// CHECK:STDOUT: }
// CHECK:STDOUT: