Unify handling of transitive imports between current and other packages. (#3971)

This makes cross-package `export import` work. Note collisions still
occur with cross-package "export name".
This commit is contained in:
Jon Ross-Perkins
2024-05-22 15:56:22 +00:00
committed by GitHub
parent a1ff49af03
commit 41a84222c2
6 changed files with 388 additions and 160 deletions
+58 -59
View File
@@ -212,6 +212,58 @@ struct UnitInfo {
UnitInfo* api_for_impl = nullptr;
};
// Collects transitive imports, handling deduplication.
static auto CollectTransitiveImports(const UnitInfo::PackageImports& imports,
int total_ir_count)
-> llvm::SmallVector<SemIR::ImportIR> {
llvm::SmallVector<SemIR::ImportIR> results;
// Track whether an IR was imported in full, including `export import`. This
// distinguishes from IRs that are indirectly added without all names being
// exported to this IR.
llvm::SmallVector<int> ir_to_result_index(total_ir_count, -1);
// First add direct imports. This means that if an entity is imported both
// directly and indirectly, the import path will reflect the direct import.
for (const auto& import : imports.imports) {
const auto& direct_ir = **import.unit_info->unit->sem_ir;
ir_to_result_index[direct_ir.check_ir_id().index] = results.size();
results.push_back({.node_id = import.names.node_id,
.sem_ir = &direct_ir,
.is_export = import.names.is_export});
}
// Loop through direct imports for any indirect exports. The underlying vector
// is appended during iteration, so take the size first.
const int direct_imports = results.size();
for (int direct_index : llvm::seq(direct_imports)) {
bool is_export = results[direct_index].is_export;
for (const auto& indirect_ir :
results[direct_index].sem_ir->import_irs().array_ref()) {
if (!indirect_ir.is_export) {
continue;
}
auto& indirect_index =
ir_to_result_index[indirect_ir.sem_ir->check_ir_id().index];
if (indirect_index == -1) {
indirect_index = results.size();
// TODO: In the case of a recursive `export import`, this only points at
// the outermost import. May want something that better reflects the
// recursion.
results.push_back({.node_id = results[direct_index].node_id,
.sem_ir = indirect_ir.sem_ir,
.is_export = is_export});
} else if (is_export) {
results[indirect_index].is_export = true;
}
}
}
return results;
}
// Imports the current package.
static auto ImportCurrentPackage(Context& context, UnitInfo& unit_info,
int total_ir_count,
@@ -228,60 +280,13 @@ static auto ImportCurrentPackage(Context& context, UnitInfo& unit_info,
UnitInfo::PackageImports& self_import =
unit_info.package_imports[self_import_map_it->second];
// Track whether an IR was imported in full, including `export import`. This
// distinguishes from IRs that are indirectly added without all names being
// exported to this IR.
llvm::SmallVector<bool> imported_irs(total_ir_count, false);
if (self_import.has_load_error) {
context.name_scopes().Get(SemIR::NameScopeId::Package).has_error = true;
}
for (const auto& import : self_import.imports) {
const auto& import_sem_ir = **import.unit_info->unit->sem_ir;
auto& imported_ir = imported_irs[import_sem_ir.check_ir_id().index];
if (!imported_ir) {
imported_ir = true;
// Import the IR and its exported imports.
ImportLibraryFromCurrentPackage(context, namespace_type_id,
import.names.node_id, import_sem_ir,
import.names.is_export);
for (const auto& indirect_ir : import_sem_ir.import_irs().array_ref()) {
if (indirect_ir.is_export) {
auto& imported_indirect_ir =
imported_irs[indirect_ir.sem_ir->check_ir_id().index];
if (!imported_indirect_ir) {
imported_indirect_ir = true;
ImportLibraryFromCurrentPackage(
context, namespace_type_id, import.names.node_id,
*indirect_ir.sem_ir, import.names.is_export);
} else if (import.names.is_export) {
// The indirect IR was previously indirectly imported, but it's
// found through `export import`. We need to mark it for re-export.
context.import_irs()
.Get(context.GetImportIRId(*indirect_ir.sem_ir))
.is_export = true;
}
}
}
} else if (import.names.is_export) {
// The IR was previously indirectly imported, but it's `export import`.
// We need to mark it -- and transitive `export import`s -- for re-export.
context.import_irs().Get(context.GetImportIRId(import_sem_ir)).is_export =
true;
for (const auto& indirect_ir : import_sem_ir.import_irs().array_ref()) {
if (indirect_ir.is_export) {
context.import_irs()
.Get(context.GetImportIRId(*indirect_ir.sem_ir))
.is_export = true;
}
}
}
}
ImportLibrariesFromCurrentPackage(
context, namespace_type_id,
CollectTransitiveImports(self_import, total_ir_count));
context.scope_stack().Push(
package_inst_id, SemIR::NameScopeId::Package,
@@ -346,17 +351,11 @@ static auto InitPackageScopeAndImports(Context& context, UnitInfo& unit_info,
continue;
}
llvm::SmallVector<SemIR::ImportIR> import_irs;
for (auto import : package_imports.imports) {
import_irs.push_back({.node_id = import.names.node_id,
.sem_ir = &**import.unit_info->unit->sem_ir,
.is_export = false});
CARBON_CHECK(!import.names.is_export)
<< "Imports from other packages can't be exported.";
}
ImportLibrariesFromOtherPackage(
context, namespace_type_id, package_imports.node_id,
package_imports.package_id, import_irs, package_imports.has_load_error);
package_imports.package_id,
CollectTransitiveImports(package_imports, total_ir_count),
package_imports.has_load_error);
}
}
+38 -35
View File
@@ -288,48 +288,51 @@ static auto AddImportRefOrMerge(Context& context, SemIR::ImportIRId ir_id,
}
}
auto ImportLibraryFromCurrentPackage(Context& context,
SemIR::TypeId namespace_type_id,
Parse::ImportDeclId node_id,
const SemIR::File& import_sem_ir,
bool is_export) -> void {
auto ir_id = AddImportIR(
context,
{.node_id = node_id, .sem_ir = &import_sem_ir, .is_export = is_export});
auto ImportLibrariesFromCurrentPackage(
Context& context, SemIR::TypeId namespace_type_id,
llvm::ArrayRef<SemIR::ImportIR> import_irs) -> void {
for (auto import_ir : import_irs) {
auto ir_id = AddImportIR(context, import_ir);
context.import_ir_constant_values()[ir_id.index].Set(
SemIR::InstId::PackageNamespace,
context.constant_values().Get(SemIR::InstId::PackageNamespace));
context.import_ir_constant_values()[ir_id.index].Set(
SemIR::InstId::PackageNamespace,
context.constant_values().Get(SemIR::InstId::PackageNamespace));
for (const auto import_inst_id :
import_sem_ir.inst_blocks().Get(SemIR::InstBlockId::Exports)) {
auto import_inst = import_sem_ir.insts().Get(import_inst_id);
auto [import_name_id, import_enclosing_scope_id] =
GetImportName(import_sem_ir, import_inst);
for (const auto import_inst_id :
import_ir.sem_ir->inst_blocks().Get(SemIR::InstBlockId::Exports)) {
auto import_inst = import_ir.sem_ir->insts().Get(import_inst_id);
auto [import_name_id, import_enclosing_scope_id] =
GetImportName(*import_ir.sem_ir, import_inst);
llvm::DenseMap<SemIR::NameScopeId, SemIR::NameScopeId> copied_namespaces;
llvm::DenseMap<SemIR::NameScopeId, SemIR::NameScopeId> copied_namespaces;
auto name_id = CopyNameFromImportIR(context, import_sem_ir, import_name_id);
SemIR::NameScopeId enclosing_scope_id = CopyEnclosingNameScopesFromImportIR(
context, namespace_type_id, import_sem_ir, ir_id,
import_enclosing_scope_id, copied_namespaces);
auto name_id =
CopyNameFromImportIR(context, *import_ir.sem_ir, import_name_id);
SemIR::NameScopeId enclosing_scope_id =
CopyEnclosingNameScopesFromImportIR(
context, namespace_type_id, *import_ir.sem_ir, ir_id,
import_enclosing_scope_id, copied_namespaces);
if (auto import_namespace_inst = import_inst.TryAs<SemIR::Namespace>()) {
// Namespaces are always imported because they're essential for
// qualifiers, and the type is simple.
CopySingleNameScopeFromImportIR(
context, namespace_type_id, copied_namespaces, ir_id, import_inst_id,
import_namespace_inst->name_scope_id, enclosing_scope_id, name_id);
} else {
AddImportRefOrMerge(context, ir_id, import_sem_ir, import_inst_id,
enclosing_scope_id, name_id);
if (auto import_namespace_inst = import_inst.TryAs<SemIR::Namespace>()) {
// Namespaces are always imported because they're essential for
// qualifiers, and the type is simple.
CopySingleNameScopeFromImportIR(
context, namespace_type_id, copied_namespaces, ir_id,
import_inst_id, import_namespace_inst->name_scope_id,
enclosing_scope_id, name_id);
} else {
AddImportRefOrMerge(context, ir_id, *import_ir.sem_ir, import_inst_id,
enclosing_scope_id, name_id);
}
}
}
// If an import of the current package caused an error for the imported
// file, it transitively affects the current file too.
if (import_sem_ir.name_scopes().Get(SemIR::NameScopeId::Package).has_error) {
context.name_scopes().Get(SemIR::NameScopeId::Package).has_error = true;
// If an import of the current package caused an error for the imported
// file, it transitively affects the current file too.
if (import_ir.sem_ir->name_scopes()
.Get(SemIR::NameScopeId::Package)
.has_error) {
context.name_scopes().Get(SemIR::NameScopeId::Package).has_error = true;
}
}
}
+9 -12
View File
@@ -11,19 +11,16 @@
namespace Carbon::Check {
// Add imports from a single library in the current package. This pulls in all
// names; conflicts for things such as `package.a.b.c` will be flagged even
// though they are several layers deep.
auto ImportLibraryFromCurrentPackage(Context& context,
SemIR::TypeId namespace_type_id,
Parse::ImportDeclId node_id,
const SemIR::File& import_sem_ir,
bool is_export) -> void;
// Add the current package's imports to name lookup. This pulls in all names;
// conflicts for things such as `package.a.b.c` will be flagged even though they
// are several layers deep.
auto ImportLibrariesFromCurrentPackage(
Context& context, SemIR::TypeId namespace_type_id,
llvm::ArrayRef<SemIR::ImportIR> import_irs) -> void;
// Adds another package's imports to name lookup, with all libraries together.
// This only adds the package name to lookup, so that `package.ImportedPackage`
// will resolve, and will provide a name scope that can be used for further
// qualified name lookups.
// Adds another package's imports to name lookup. This only adds the package
// name to lookup, so that `package.ImportedPackage` will resolve, and will
// provide a name scope that can be used for further qualified name lookups.
//
// import_irs may be empty. has_load_error is used to indicate if any library in
// the package failed to import correctly.
@@ -28,6 +28,12 @@ package Other library "export_import_copy";
export import library "base";
// --- export_import_indirect.carbon
package Other library "export_import_indirect";
export import library "export_import";
// --- export_name.carbon
package Other library "export_name";
@@ -44,33 +50,41 @@ import library "base";
export C;
// --- export_name_indirect.carbon
package Other library "export_name_indirect";
import library "export_name";
export C;
// ============================================================================
// Test files
// ============================================================================
// --- fail_todo_use_export_import.carbon
// --- use_export_import.carbon
library "use_export_import";
import Other library "export_import";
// CHECK:STDERR: fail_todo_use_export_import.carbon:[[@LINE+4]]:8: ERROR: Name `C` not found.
// CHECK:STDERR: var c: Other.C = {.x = ()};
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
var c: Other.C = {.x = ()};
// --- fail_todo_use_export_import_both.carbon
// --- use_export_import_with_copy.carbon
library "use_export_import_both";
library "use_export_import_with_copy";
import Other library "export_import";
import Other library "export_import_copy";
// CHECK:STDERR: fail_todo_use_export_import_both.carbon:[[@LINE+4]]:8: ERROR: Name `C` not found.
// CHECK:STDERR: var c: Other.C = {.x = ()};
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
var c: Other.C = {.x = ()};
// --- use_export_import_indirect.carbon
library "use_export_import_indirect";
import Other library "export_import_indirect";
var c: Other.C = {.x = ()};
// --- use_export_name.carbon
@@ -81,12 +95,12 @@ import Other library "export_name";
var c: Other.C = {.x = ()};
// --- fail_todo_use_export_name_both.carbon
// --- fail_todo_use_export_name_with_copy.carbon
library "use_export_name_both";
library "use_export_name_with_copy";
import Other library "export_name";
// CHECK:STDERR: fail_todo_use_export_name_both.carbon:[[@LINE+18]]:1: In import.
// 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.
@@ -95,7 +109,7 @@ import Other library "export_name";
// 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_both.carbon:[[@LINE-10]]:1: In import.
// 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.
@@ -106,29 +120,32 @@ import Other library "export_name";
// CHECK:STDERR: ^~~~~~~~~
import Other library "export_name_copy";
// CHECK:STDERR: fail_todo_use_export_name_both.carbon:[[@LINE+4]]:8: In name lookup for `C`.
// 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
library "use_export_name_indirect";
import Other library "export_name_indirect";
var c: Other.C = {.x = ()};
// --- fail_todo_use_export_all.carbon
library "use_export_all";
import Other library "export_import";
import Other library "export_name";
import Other library "export_import_copy";
// CHECK:STDERR: fail_todo_use_export_all.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: 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: ^~~~~~~~~
// CHECK:STDERR: fail_todo_use_export_all.carbon:[[@LINE-11]]:1: In import.
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.
@@ -137,8 +154,59 @@ import Other library "export_import_copy";
// 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: ^~~~~~~
@@ -188,6 +256,15 @@ var c: Other.C = {.x = ()};
// CHECK:STDOUT: %import_ref = import_ref ir1, inst+1, unloaded
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- export_import_indirect.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref = import_ref ir2, inst+1, unloaded
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- export_name.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
@@ -236,38 +313,84 @@ var c: Other.C = {.x = ()};
// CHECK:STDOUT: .x = file.%import_ref.3
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_use_export_import.carbon
// CHECK:STDOUT: --- export_name_indirect.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: .C = %C
// CHECK:STDOUT: }
// 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: %C: type = export 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:
// CHECK:STDOUT: --- use_export_import.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: %.3: type = ptr_type {.x: ()} [template]
// CHECK:STDOUT: %tuple: () = tuple_value () [template]
// CHECK:STDOUT: %struct: C = struct_value (%tuple) [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: %C.ref: <error> = name_ref C, <error> [template = <error>]
// CHECK:STDOUT: %c.var: ref <error> = var c
// CHECK:STDOUT: %c: ref <error> = bind_name c, %c.var
// CHECK:STDOUT: %import_ref.1: type = import_ref ir2, inst+1, loaded [template = constants.%C]
// CHECK:STDOUT: %import_ref.2 = import_ref ir2, inst+2, unloaded
// CHECK:STDOUT: %import_ref.3 = import_ref ir2, inst+7, 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: }
// 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:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc10_25: () = tuple_literal ()
// CHECK:STDOUT: %.loc10_26: {.x: ()} = struct_literal (%.loc10_25)
// CHECK:STDOUT: assign file.%c.var, <error>
// CHECK:STDOUT: %.loc6_25.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc6_26.1: {.x: ()} = struct_literal (%.loc6_25.1)
// CHECK:STDOUT: %.loc6_26.2: ref () = class_element_access file.%c.var, element0
// CHECK:STDOUT: %.loc6_25.2: init () = tuple_init () to %.loc6_26.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc6_26.3: init () = converted %.loc6_25.1, %.loc6_25.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc6_26.4: init C = class_init (%.loc6_26.3), file.%c.var [template = constants.%struct]
// CHECK:STDOUT: %.loc6_27: init C = converted %.loc6_26.1, %.loc6_26.4 [template = constants.%struct]
// CHECK:STDOUT: assign file.%c.var, %.loc6_27
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_use_export_import_both.carbon
// CHECK:STDOUT: --- use_export_import_with_copy.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: %.3: type = ptr_type {.x: ()} [template]
// CHECK:STDOUT: %tuple: () = tuple_value () [template]
// CHECK:STDOUT: %struct: C = struct_value (%tuple) [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -277,16 +400,75 @@ var c: Other.C = {.x = ()};
// CHECK:STDOUT: }
// CHECK:STDOUT: %Other: <namespace> = namespace [template] {}
// CHECK:STDOUT: %Other.ref: <namespace> = name_ref Other, %Other [template = %Other]
// CHECK:STDOUT: %C.ref: <error> = name_ref C, <error> [template = <error>]
// CHECK:STDOUT: %c.var: ref <error> = var c
// CHECK:STDOUT: %c: ref <error> = bind_name c, %c.var
// CHECK:STDOUT: %import_ref.1: type = import_ref ir3, inst+1, loaded [template = constants.%C]
// CHECK:STDOUT: %import_ref.2 = import_ref ir3, inst+2, unloaded
// CHECK:STDOUT: %import_ref.3 = import_ref ir3, inst+7, 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: }
// 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:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc11_25: () = tuple_literal ()
// CHECK:STDOUT: %.loc11_26: {.x: ()} = struct_literal (%.loc11_25)
// CHECK:STDOUT: assign file.%c.var, <error>
// 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:
// CHECK:STDOUT: --- use_export_import_indirect.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: %.3: type = ptr_type {.x: ()} [template]
// CHECK:STDOUT: %tuple: () = tuple_value () [template]
// CHECK:STDOUT: %struct: C = struct_value (%tuple) [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 ir3, inst+1, loaded [template = constants.%C]
// CHECK:STDOUT: %import_ref.2 = import_ref ir3, inst+2, unloaded
// CHECK:STDOUT: %import_ref.3 = import_ref ir3, inst+7, 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: }
// 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:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc6_25.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc6_26.1: {.x: ()} = struct_literal (%.loc6_25.1)
// CHECK:STDOUT: %.loc6_26.2: ref () = class_element_access file.%c.var, element0
// CHECK:STDOUT: %.loc6_25.2: init () = tuple_init () to %.loc6_26.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc6_26.3: init () = converted %.loc6_25.1, %.loc6_25.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc6_26.4: init C = class_init (%.loc6_26.3), file.%c.var [template = constants.%struct]
// CHECK:STDOUT: %.loc6_27: init C = converted %.loc6_26.1, %.loc6_26.4 [template = constants.%struct]
// CHECK:STDOUT: assign file.%c.var, %.loc6_27
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -335,7 +517,7 @@ var c: Other.C = {.x = ()};
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_use_export_name_both.carbon
// CHECK:STDOUT: --- fail_todo_use_export_name_with_copy.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [template]
@@ -381,6 +563,51 @@ var c: Other.C = {.x = ()};
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- use_export_name_indirect.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: %.3: type = ptr_type {.x: ()} [template]
// CHECK:STDOUT: %tuple: () = tuple_value () [template]
// CHECK:STDOUT: %struct: C = struct_value (%tuple) [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: %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: }
// 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:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc6_25.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc6_26.1: {.x: ()} = struct_literal (%.loc6_25.1)
// CHECK:STDOUT: %.loc6_26.2: ref () = class_element_access file.%c.var, element0
// CHECK:STDOUT: %.loc6_25.2: init () = tuple_init () to %.loc6_26.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc6_26.3: init () = converted %.loc6_25.1, %.loc6_25.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc6_26.4: init C = class_init (%.loc6_26.3), file.%c.var [template = constants.%struct]
// CHECK:STDOUT: %.loc6_27: init C = converted %.loc6_26.1, %.loc6_26.4 [template = constants.%struct]
// CHECK:STDOUT: assign file.%c.var, %.loc6_27
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_use_export_all.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
@@ -403,6 +630,8 @@ var c: Other.C = {.x = ()};
// 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
@@ -416,14 +645,14 @@ var c: Other.C = {.x = ()};
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc30_25.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc30_26.1: {.x: ()} = struct_literal (%.loc30_25.1)
// CHECK:STDOUT: %.loc30_26.2: ref () = class_element_access file.%c.var, element0
// CHECK:STDOUT: %.loc30_25.2: init () = tuple_init () to %.loc30_26.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc30_26.3: init () = converted %.loc30_25.1, %.loc30_25.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc30_26.4: init C = class_init (%.loc30_26.3), file.%c.var [template = constants.%struct]
// CHECK:STDOUT: %.loc30_27: init C = converted %.loc30_26.1, %.loc30_26.4 [template = constants.%struct]
// CHECK:STDOUT: assign file.%c.var, %.loc30_27
// 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: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -599,9 +599,9 @@ var indirect_c: C = {.x = ()};
// CHECK:STDOUT: .C = %import_ref.1
// CHECK:STDOUT: .c = %c
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.1: type = import_ref ir2, inst+1, loaded [template = constants.%C]
// CHECK:STDOUT: %import_ref.2 = import_ref ir2, inst+7, unloaded
// CHECK:STDOUT: %import_ref.3 = import_ref ir2, inst+2, unloaded
// CHECK:STDOUT: %import_ref.1: type = import_ref ir3, inst+1, loaded [template = constants.%C]
// CHECK:STDOUT: %import_ref.2 = import_ref ir3, inst+7, unloaded
// CHECK:STDOUT: %import_ref.3 = import_ref ir3, 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
@@ -443,14 +443,14 @@ var d: D = {.y = ()};
// 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: type = import_ref ir4, inst+11, loaded [template = constants.%D]
// CHECK:STDOUT: %import_ref.2: type = import_ref ir5, 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.5 = import_ref ir4, inst+12, unloaded
// CHECK:STDOUT: %import_ref.6 = import_ref ir4, inst+16, unloaded
// CHECK:STDOUT: %import_ref.5 = import_ref ir5, inst+12, unloaded
// CHECK:STDOUT: %import_ref.6 = import_ref ir5, 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