From 41a84222c2ca69d8130388e6592db63b27eec6e0 Mon Sep 17 00:00:00 2001 From: Jon Ross-Perkins Date: Wed, 22 May 2024 08:56:22 -0700 Subject: [PATCH] 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". --- toolchain/check/check.cpp | 117 ++++--- toolchain/check/import.cpp | 73 ++-- toolchain/check/import.h | 21 +- .../no_prelude/cross_package_export.carbon | 325 +++++++++++++++--- .../packages/no_prelude/export_import.carbon | 6 +- .../packages/no_prelude/export_mixed.carbon | 6 +- 6 files changed, 388 insertions(+), 160 deletions(-) diff --git a/toolchain/check/check.cpp b/toolchain/check/check.cpp index 79982d35c798..adc2b1c29625 100644 --- a/toolchain/check/check.cpp +++ b/toolchain/check/check.cpp @@ -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 { + llvm::SmallVector 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 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 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 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); } } diff --git a/toolchain/check/import.cpp b/toolchain/check/import.cpp index 6863c5e0c70c..5890192d8165 100644 --- a/toolchain/check/import.cpp +++ b/toolchain/check/import.cpp @@ -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 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 copied_namespaces; + llvm::DenseMap 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()) { - // 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()) { + // 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; + } } } diff --git a/toolchain/check/import.h b/toolchain/check/import.h index d7ba0d98f4d0..5e216aab51bc 100644 --- a/toolchain/check/import.h +++ b/toolchain/check/import.h @@ -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 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. diff --git a/toolchain/check/testdata/packages/no_prelude/cross_package_export.carbon b/toolchain/check/testdata/packages/no_prelude/cross_package_export.carbon index 87fb10b8210f..7d3d87a41e59 100644 --- a/toolchain/check/testdata/packages/no_prelude/cross_package_export.carbon +++ b/toolchain/check/testdata/packages/no_prelude/cross_package_export.carbon @@ -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 [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 [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 [template] { // CHECK:STDOUT: .Other = %Other // CHECK:STDOUT: .c = %c // CHECK:STDOUT: } // CHECK:STDOUT: %Other: = namespace [template] {} // CHECK:STDOUT: %Other.ref: = name_ref Other, %Other [template = %Other] -// CHECK:STDOUT: %C.ref: = name_ref C, [template = ] -// CHECK:STDOUT: %c.var: ref = var c -// CHECK:STDOUT: %c: ref = 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, +// 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 [template] {} // CHECK:STDOUT: %Other.ref: = name_ref Other, %Other [template = %Other] -// CHECK:STDOUT: %C.ref: = name_ref C, [template = ] -// CHECK:STDOUT: %c.var: ref = var c -// CHECK:STDOUT: %c: ref = 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, +// 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 [template] { +// CHECK:STDOUT: .Other = %Other +// CHECK:STDOUT: .c = %c +// CHECK:STDOUT: } +// CHECK:STDOUT: %Other: = namespace [template] {} +// CHECK:STDOUT: %Other.ref: = 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 [template] { +// CHECK:STDOUT: .Other = %Other +// CHECK:STDOUT: .c = %c +// CHECK:STDOUT: } +// CHECK:STDOUT: %Other: = namespace [template] {} +// CHECK:STDOUT: %Other.ref: = 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: diff --git a/toolchain/check/testdata/packages/no_prelude/export_import.carbon b/toolchain/check/testdata/packages/no_prelude/export_import.carbon index f660f0843ed4..0a1d5668e48b 100644 --- a/toolchain/check/testdata/packages/no_prelude/export_import.carbon +++ b/toolchain/check/testdata/packages/no_prelude/export_import.carbon @@ -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 diff --git a/toolchain/check/testdata/packages/no_prelude/export_mixed.carbon b/toolchain/check/testdata/packages/no_prelude/export_mixed.carbon index 83efcf38a999..3878b28bd802 100644 --- a/toolchain/check/testdata/packages/no_prelude/export_mixed.carbon +++ b/toolchain/check/testdata/packages/no_prelude/export_mixed.carbon @@ -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