From dffe4a36de1ddd96e4795befc7aad4b890e32e07 Mon Sep 17 00:00:00 2001 From: Jon Ross-Perkins Date: Tue, 2 Apr 2024 10:44:55 -0700 Subject: [PATCH] When merging functions, detect uses of imports prior to a redecl. (#3836) LookupNameInDecl is only called from DeclNameStack, but I'm adding mark_imports_used there because it feels more consistent. Not sure if we want a better API boundary. I admit I'm also suspicious of its call to LookupInCurrentScope but maybe it's okay due to how imports work. I was choosing to print multiple diagnostics when a declaration is previously used _and_ doesn't match because I think the "previously used" is more important, but the "doesn't match" may give an additional hint about why it didn't work. The merge.h utility function is because I think we can follow a similar model for identifying errors with other declarations: classes, interfaces, etc. --- toolchain/check/context.cpp | 26 +- toolchain/check/context.h | 6 +- toolchain/check/decl_name_stack.cpp | 3 +- toolchain/check/handle_function.cpp | 15 +- toolchain/check/impl.cpp | 4 +- toolchain/check/merge.cpp | 25 + toolchain/check/merge.h | 14 + .../testdata/class/fail_import_misuses.carbon | 2 +- .../fail_todo_import_forward_decl.carbon | 2 +- .../function/declaration/import.carbon | 458 +++++++++++++++--- .../function/definition/import.carbon | 6 +- ..._conflict_imported_namespace_second.carbon | 2 +- .../packages/cross_package_import.carbon | 2 +- toolchain/diagnostics/diagnostic_kind.def | 2 + 14 files changed, 471 insertions(+), 96 deletions(-) diff --git a/toolchain/check/context.cpp b/toolchain/check/context.cpp index 4ef1fc39a33d..303a0fb75cbf 100644 --- a/toolchain/check/context.cpp +++ b/toolchain/check/context.cpp @@ -227,7 +227,8 @@ auto Context::AddNameToLookup(SemIR::NameId name_id, SemIR::InstId target_id) } auto Context::LookupNameInDecl(SemIR::LocId loc_id, SemIR::NameId name_id, - SemIR::NameScopeId scope_id) -> SemIR::InstId { + SemIR::NameScopeId scope_id, + bool mark_imports_used) -> SemIR::InstId { if (!scope_id.is_valid()) { // Look for a name in the current scope only. There are two cases where the // name would be in an outer scope: @@ -263,7 +264,8 @@ auto Context::LookupNameInDecl(SemIR::LocId loc_id, SemIR::NameId name_id, // // // Error, no `F` in `B`. // fn B.F() {} - return LookupNameInExactScope(loc_id, name_id, name_scopes().Get(scope_id)); + return LookupNameInExactScope(loc_id, name_id, name_scopes().Get(scope_id), + mark_imports_used); } } @@ -298,8 +300,8 @@ auto Context::LookupUnqualifiedName(Parse::NodeId node_id, // Handles lookup through the import_ir_scopes for LookupNameInExactScope. static auto LookupInImportIRScopes(Context& context, SemIRLoc loc, SemIR::NameId name_id, - const SemIR::NameScope& scope) - -> SemIR::InstId { + const SemIR::NameScope& scope, + bool mark_imports_used) -> SemIR::InstId { auto identifier_id = name_id.AsIdentifierId(); llvm::StringRef identifier; if (identifier_id.is_valid()) { @@ -342,7 +344,8 @@ static auto LookupInImportIRScopes(Context& context, SemIRLoc loc, if (result_id.is_valid()) { MergeImportRef(context, import_inst_id, result_id); } else { - LoadImportRef(context, import_inst_id, loc); + LoadImportRef(context, import_inst_id, + mark_imports_used ? loc : SemIR::LocId::Invalid); result_id = import_inst_id; } } @@ -351,14 +354,16 @@ static auto LookupInImportIRScopes(Context& context, SemIRLoc loc, } auto Context::LookupNameInExactScope(SemIRLoc loc, SemIR::NameId name_id, - const SemIR::NameScope& scope) - -> SemIR::InstId { + const SemIR::NameScope& scope, + bool mark_imports_used) -> SemIR::InstId { if (auto it = scope.names.find(name_id); it != scope.names.end()) { - LoadImportRef(*this, it->second, loc); + LoadImportRef(*this, it->second, + mark_imports_used ? loc : SemIR::LocId::Invalid); return it->second; } if (!scope.import_ir_scopes.empty()) { - return LookupInImportIRScopes(*this, loc, name_id, scope); + return LookupInImportIRScopes(*this, loc, name_id, scope, + mark_imports_used); } return SemIR::InstId::Invalid; } @@ -375,7 +380,8 @@ auto Context::LookupQualifiedName(Parse::NodeId node_id, SemIR::NameId name_id, const auto& scope = name_scopes().Get(scope_ids.pop_back_val()); has_error |= scope.has_error; - auto scope_result_id = LookupNameInExactScope(node_id, name_id, scope); + auto scope_result_id = LookupNameInExactScope(node_id, name_id, scope, + /*mark_imports_used=*/true); if (!scope_result_id.is_valid()) { // Nothing found in this scope: also look in its extended scopes. auto extended = llvm::reverse(scope.extended_scopes); diff --git a/toolchain/check/context.h b/toolchain/check/context.h index bebbf72373f1..86050141d048 100644 --- a/toolchain/check/context.h +++ b/toolchain/check/context.h @@ -103,7 +103,8 @@ class Context { // declaration, returning the referenced instruction. If scope_id is invalid, // uses the current contextual scope. auto LookupNameInDecl(SemIR::LocId loc_id, SemIR::NameId name_id, - SemIR::NameScopeId scope_id) -> SemIR::InstId; + SemIR::NameScopeId scope_id, bool mark_imports_used) + -> SemIR::InstId; // Performs an unqualified name lookup, returning the referenced instruction. auto LookupUnqualifiedName(Parse::NodeId node_id, SemIR::NameId name_id) @@ -113,7 +114,8 @@ class Context { // instruction. Does not look into extended scopes. Returns an invalid // instruction if the name is not found. auto LookupNameInExactScope(SemIRLoc loc, SemIR::NameId name_id, - const SemIR::NameScope& scope) -> SemIR::InstId; + const SemIR::NameScope& scope, + bool mark_imports_used) -> SemIR::InstId; // Performs a qualified name lookup in a specified scope and in scopes that // it extends, returning the referenced instruction. diff --git a/toolchain/check/decl_name_stack.cpp b/toolchain/check/decl_name_stack.cpp index bbc9971fda8c..ddc6cd1ab082 100644 --- a/toolchain/check/decl_name_stack.cpp +++ b/toolchain/check/decl_name_stack.cpp @@ -168,7 +168,8 @@ auto DeclNameStack::ApplyNameQualifierTo(NameContext& name_context, if (TryResolveQualifier(name_context, loc_id)) { // For identifier nodes, we need to perform a lookup on the identifier. auto resolved_inst_id = context_->LookupNameInDecl( - name_context.loc_id, name_id, name_context.target_scope_id); + name_context.loc_id, name_id, name_context.target_scope_id, + /*mark_imports_used=*/false); if (!resolved_inst_id.is_valid()) { // Invalid indicates an unresolved name. Store it and return. name_context.state = NameContext::State::Unresolved; diff --git a/toolchain/check/handle_function.cpp b/toolchain/check/handle_function.cpp index 95ff38606c2d..28cbe3185395 100644 --- a/toolchain/check/handle_function.cpp +++ b/toolchain/check/handle_function.cpp @@ -8,6 +8,7 @@ #include "toolchain/check/decl_state.h" #include "toolchain/check/function.h" #include "toolchain/check/interface.h" +#include "toolchain/check/merge.h" #include "toolchain/check/modifiers.h" #include "toolchain/parse/tree_node_diagnostic_converter.h" #include "toolchain/sem_ir/builtin_function_kind.h" @@ -168,19 +169,13 @@ static auto BuildFunctionDecl(Context& context, auto prev_id = context.decl_name_stack().LookupOrAddName(name_context, lookup_result_id); if (prev_id.is_valid()) { - auto prev_inst = context.insts().Get(prev_id); - bool prev_is_import = false; + auto prev_inst = ResolvePrevInstForMerge(context, node_id, prev_id); - if (prev_inst.Is()) { - prev_inst = - context.insts().Get(context.constant_values().Get(prev_id).inst_id()); - prev_is_import = true; - } - - if (auto existing_function_decl = prev_inst.TryAs()) { + if (auto existing_function_decl = + prev_inst.inst.TryAs()) { if (MergeFunctionRedecl(context, node_id, function_info, is_definition, existing_function_decl->function_id, - prev_is_import)) { + prev_inst.is_import)) { // When merging, use the existing function rather than adding a new one. function_decl.function_id = existing_function_decl->function_id; } diff --git a/toolchain/check/impl.cpp b/toolchain/check/impl.cpp index e5e9e3ee0028..8120966d5a03 100644 --- a/toolchain/check/impl.cpp +++ b/toolchain/check/impl.cpp @@ -92,8 +92,8 @@ static auto BuildInterfaceWitness( auto decl = context.insts().Get(const_id.inst_id()); if (auto fn_decl = decl.TryAs()) { auto& fn = context.functions().Get(fn_decl->function_id); - auto impl_decl_id = - context.LookupNameInExactScope(decl_id, fn.name_id, impl_scope); + auto impl_decl_id = context.LookupNameInExactScope( + decl_id, fn.name_id, impl_scope, /*mark_imports_used=*/true); if (impl_decl_id.is_valid()) { used_decl_ids.push_back(impl_decl_id); table.push_back(CheckAssociatedFunctionImplementation( diff --git a/toolchain/check/merge.cpp b/toolchain/check/merge.cpp index 61e120b2a39b..fbcddb38e47a 100644 --- a/toolchain/check/merge.cpp +++ b/toolchain/check/merge.cpp @@ -6,9 +6,34 @@ #include "toolchain/check/function.h" #include "toolchain/check/import_ref.h" +#include "toolchain/sem_ir/typed_insts.h" namespace Carbon::Check { +auto ResolvePrevInstForMerge(Context& context, Parse::NodeId node_id, + SemIR::InstId prev_inst_id) -> PrevInstForMerge { + PrevInstForMerge prev_inst{.inst = context.insts().Get(prev_inst_id), + .is_import = false}; + if (auto import_ref = prev_inst.inst.TryAs()) { + CARBON_DIAGNOSTIC( + RedeclOfUsedImport, Error, + "Redeclaration of imported entity that was previously used."); + CARBON_DIAGNOSTIC(UsedImportLoc, Note, "Import used here."); + context.emitter() + .Build(node_id, RedeclOfUsedImport) + .Note(import_ref->used_id, UsedImportLoc) + .Emit(); + + } else if (!prev_inst.inst.Is()) { + return prev_inst; + } + + prev_inst.is_import = true; + prev_inst.inst = context.insts().Get( + context.constant_values().Get(prev_inst_id).inst_id()); + return prev_inst; +} + // Returns the instruction to consider when merging the given inst_id. Returns // nullopt if merging is infeasible and no diagnostic should be printed. static auto ResolveMergeableInst(Context& context, SemIR::InstId inst_id) diff --git a/toolchain/check/merge.h b/toolchain/check/merge.h index ab5252577b5e..dc697ae18d3f 100644 --- a/toolchain/check/merge.h +++ b/toolchain/check/merge.h @@ -10,6 +10,20 @@ namespace Carbon::Check { +struct PrevInstForMerge { + // The resolved instruction. + SemIR::Inst inst; + // Whether an import was encountered during resolution. + bool is_import; +}; + +// Resolves prev_inst_id for merging (or name conflicts). This handles imports +// to return the instruction relevant for a merge. If an import is found and was +// previously used, it notes it, although an invalid redeclaration may diagnose +// for other reasons too. +auto ResolvePrevInstForMerge(Context& context, Parse::NodeId node_id, + SemIR::InstId prev_inst_id) -> PrevInstForMerge; + // Merges an import ref at new_inst_id another at prev_inst_id. May print a // diagnostic if merging is invalid. auto MergeImportRef(Context& context, SemIR::InstId new_inst_id, diff --git a/toolchain/check/testdata/class/fail_import_misuses.carbon b/toolchain/check/testdata/class/fail_import_misuses.carbon index cce145cf3e4d..4626f5e2435a 100644 --- a/toolchain/check/testdata/class/fail_import_misuses.carbon +++ b/toolchain/check/testdata/class/fail_import_misuses.carbon @@ -82,7 +82,7 @@ var a: Incomplete; // CHECK:STDOUT: .Incomplete = %import_ref.2 // CHECK:STDOUT: .a = %a // CHECK:STDOUT: } -// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, loc_10 [template = constants.%Empty] +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, loaded [template = constants.%Empty] // CHECK:STDOUT: %import_ref.2: type = import_ref ir1, inst+4, loc_15 [template = constants.%Incomplete] // CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+2, unloaded // CHECK:STDOUT: %.decl: type = class_decl @.1 [template = constants.%.2] { diff --git a/toolchain/check/testdata/class/fail_todo_import_forward_decl.carbon b/toolchain/check/testdata/class/fail_todo_import_forward_decl.carbon index 7d6b57785e61..173d5ad6ba01 100644 --- a/toolchain/check/testdata/class/fail_todo_import_forward_decl.carbon +++ b/toolchain/check/testdata/class/fail_todo_import_forward_decl.carbon @@ -56,7 +56,7 @@ class ForwardDecl { // CHECK:STDOUT: package: = namespace [template] { // CHECK:STDOUT: .ForwardDecl = %import_ref // CHECK:STDOUT: } -// CHECK:STDOUT: %import_ref: type = import_ref ir1, inst+1, loc_10 [template = constants.%ForwardDecl] +// CHECK:STDOUT: %import_ref: type = import_ref ir1, inst+1, loaded [template = constants.%ForwardDecl] // CHECK:STDOUT: %.decl: type = class_decl @.1 [template = constants.%.1] { // CHECK:STDOUT: %ForwardDecl.decl: invalid = class_decl @ForwardDecl [template = constants.%ForwardDecl] {} // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/function/declaration/import.carbon b/toolchain/check/testdata/function/declaration/import.carbon index aa9a54d8fda3..86830770df8f 100644 --- a/toolchain/check/testdata/function/declaration/import.carbon +++ b/toolchain/check/testdata/function/declaration/import.carbon @@ -17,6 +17,9 @@ fn B(b: i32) -> i32; fn C(c: (i32,)) -> {.c: i32}; extern fn D(); +namespace NS; +fn NS.E(); + // --- extern_api.carbon library "extern_api" api; @@ -26,6 +29,9 @@ extern fn B(b: i32) -> i32; extern fn C(c: (i32,)) -> {.c: i32}; extern fn D(); +namespace NS; +extern fn NS.E(); + // ============================================================================ // Test files // ============================================================================ @@ -40,6 +46,7 @@ var a: () = A(); var b: i32 = B(1); var c: {.c: i32} = C((1,)); var d: () = D(); +var e: () = NS.E(); // --- redecl_api.carbon @@ -51,11 +58,13 @@ extern fn A(); extern fn B(b: i32) -> i32; extern fn C(c: (i32,)) -> {.c: i32}; extern fn D(); +extern fn NS.E(); var a: () = A(); var b: i32 = B(1); var c: {.c: i32} = C((1,)); var d: () = D(); +var e: () = NS.E(); // --- redecl_extern_api.carbon @@ -67,11 +76,13 @@ extern fn A(); extern fn B(b: i32) -> i32; extern fn C(c: (i32,)) -> {.c: i32}; extern fn D(); +extern fn NS.E(); var a: () = A(); var b: i32 = B(1); var c: {.c: i32} = C((1,)); var d: () = D(); +var e: () = NS.E(); // --- merge.carbon @@ -84,6 +95,7 @@ var a: () = A(); var b: i32 = B(1); var c: {.c: i32} = C((1,)); var d: () = D(); +var e: () = NS.E(); // --- merge_reverse.carbon @@ -96,6 +108,67 @@ var a: () = A(); var b: i32 = B(1); var c: {.c: i32} = C((1,)); var d: () = D(); +var e: () = NS.E(); + +// --- fail_decl_after_use.carbon + +library "decl_after_use" api; + +import library "extern_api"; + +var a: () = A(); + +// CHECK:STDERR: fail_decl_after_use.carbon:[[@LINE+7]]:1: ERROR: Redeclaration of imported entity that was previously used. +// CHECK:STDERR: fn A(); +// CHECK:STDERR: ^~~~~~~ +// CHECK:STDERR: fail_decl_after_use.carbon:[[@LINE-5]]:13: Import used here. +// CHECK:STDERR: var a: () = A(); +// CHECK:STDERR: ^ +// CHECK:STDERR: +fn A(); + +// --- fail_decl_after_use_two_errors.carbon + +library "decl_after_use_two_errors" api; + +import library "extern_api"; + +var a: () = A(); + +// CHECK:STDERR: fail_decl_after_use_two_errors.carbon:[[@LINE+17]]:1: ERROR: Redeclaration of imported entity that was previously used. +// CHECK:STDERR: fn A() -> i32; +// CHECK:STDERR: ^~~~~~~~~~~~~~ +// CHECK:STDERR: fail_decl_after_use_two_errors.carbon:[[@LINE-5]]:13: Import used here. +// CHECK:STDERR: var a: () = A(); +// CHECK:STDERR: ^ +// CHECK:STDERR: +// CHECK:STDERR: fail_decl_after_use_two_errors.carbon:[[@LINE+10]]:1: ERROR: Function redeclaration differs because return type is `i32`. +// CHECK:STDERR: fn A() -> i32; +// CHECK:STDERR: ^~~~~~~~~~~~~~ +// CHECK:STDERR: fail_decl_after_use_two_errors.carbon:[[@LINE-14]]:1: In import. +// CHECK:STDERR: import library "extern_api"; +// CHECK:STDERR: ^~~~~~ +// CHECK:STDERR: extern_api.carbon:4:1: Previously declared with no return type. +// CHECK:STDERR: extern fn A(); +// CHECK:STDERR: ^~~~~~~~~~~~~~ +// CHECK:STDERR: +fn A() -> i32; + +// --- fail_extern_after_use.carbon + +library "extern_after_use" api; + +import library "api"; + +var a: () = A(); + +// CHECK:STDERR: fail_extern_after_use.carbon:[[@LINE+6]]:1: ERROR: Redeclaration of imported entity that was previously used. +// CHECK:STDERR: extern fn A(); +// CHECK:STDERR: ^~~~~~~~~~~~~~ +// CHECK:STDERR: fail_extern_after_use.carbon:[[@LINE-5]]:13: Import used here. +// CHECK:STDERR: var a: () = A(); +// CHECK:STDERR: ^ +extern fn A(); // --- unloaded.carbon @@ -130,6 +203,7 @@ import library "extern_api"; // CHECK:STDOUT: .B = %B // CHECK:STDOUT: .C = %C // CHECK:STDOUT: .D = %D +// CHECK:STDOUT: .NS = %NS // CHECK:STDOUT: } // CHECK:STDOUT: %A: = fn_decl @A [template] {} // CHECK:STDOUT: %B: = fn_decl @B [template] { @@ -146,6 +220,10 @@ import library "extern_api"; // CHECK:STDOUT: %return.var.loc6: ref {.c: i32} = var // CHECK:STDOUT: } // CHECK:STDOUT: %D: = fn_decl @D [template] {} +// CHECK:STDOUT: %NS: = namespace [template] { +// CHECK:STDOUT: .E = %E +// CHECK:STDOUT: } +// CHECK:STDOUT: %E: = fn_decl @E [template] {} // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @A(); @@ -156,6 +234,8 @@ import library "extern_api"; // CHECK:STDOUT: // CHECK:STDOUT: extern fn @D(); // CHECK:STDOUT: +// CHECK:STDOUT: fn @E(); +// CHECK:STDOUT: // CHECK:STDOUT: --- extern_api.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -170,6 +250,7 @@ import library "extern_api"; // CHECK:STDOUT: .B = %B // CHECK:STDOUT: .C = %C // CHECK:STDOUT: .D = %D +// CHECK:STDOUT: .NS = %NS // CHECK:STDOUT: } // CHECK:STDOUT: %A: = fn_decl @A [template] {} // CHECK:STDOUT: %B: = fn_decl @B [template] { @@ -186,6 +267,10 @@ import library "extern_api"; // CHECK:STDOUT: %return.var.loc6: ref {.c: i32} = var // CHECK:STDOUT: } // CHECK:STDOUT: %D: = fn_decl @D [template] {} +// CHECK:STDOUT: %NS: = namespace [template] { +// CHECK:STDOUT: .E = %E +// CHECK:STDOUT: } +// CHECK:STDOUT: %E: = fn_decl @E [template] {} // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: extern fn @A(); @@ -196,6 +281,8 @@ import library "extern_api"; // CHECK:STDOUT: // CHECK:STDOUT: extern fn @D(); // CHECK:STDOUT: +// CHECK:STDOUT: extern fn @E(); +// CHECK:STDOUT: // CHECK:STDOUT: --- basics.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -212,15 +299,22 @@ import library "extern_api"; // CHECK:STDOUT: .B = %import_ref.2 // CHECK:STDOUT: .C = %import_ref.3 // CHECK:STDOUT: .D = %import_ref.4 +// CHECK:STDOUT: .NS = %NS // CHECK:STDOUT: .a = %a // CHECK:STDOUT: .b = %b // CHECK:STDOUT: .c = %c // CHECK:STDOUT: .d = %d +// CHECK:STDOUT: .e = %e // CHECK:STDOUT: } // CHECK:STDOUT: %import_ref.1: = import_ref ir1, inst+1, loc_15 [template = imports.%A] // CHECK:STDOUT: %import_ref.2: = import_ref ir1, inst+5, loc_24 [template = imports.%B] // CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+17, loc_39 [template = imports.%C] // CHECK:STDOUT: %import_ref.4: = import_ref ir1, inst+18, loc_53 [template = imports.%D] +// CHECK:STDOUT: %import_ref.5: = import_ref ir1, inst+19, loaded +// CHECK:STDOUT: %NS: = namespace %import_ref.5, [template] { +// CHECK:STDOUT: .E = %import_ref.6 +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.6: = import_ref ir1, inst+20, loc_65 [template = imports.%E] // CHECK:STDOUT: %.loc6_9.1: () = tuple_literal () // CHECK:STDOUT: %.loc6_9.2: type = converted %.loc6_9.1, constants.%.1 [template = constants.%.1] // CHECK:STDOUT: %a.var: ref () = var a @@ -234,6 +328,10 @@ import library "extern_api"; // CHECK:STDOUT: %.loc9_9.2: type = converted %.loc9_9.1, constants.%.1 [template = constants.%.1] // CHECK:STDOUT: %d.var: ref () = var d // CHECK:STDOUT: %d: ref () = bind_name d, %d.var +// CHECK:STDOUT: %.loc10_9.1: () = tuple_literal () +// CHECK:STDOUT: %.loc10_9.2: type = converted %.loc10_9.1, constants.%.1 [template = constants.%.1] +// CHECK:STDOUT: %e.var: ref () = var e +// CHECK:STDOUT: %e: ref () = bind_name e, %e.var // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @A(); @@ -244,6 +342,8 @@ import library "extern_api"; // CHECK:STDOUT: // CHECK:STDOUT: extern fn @D(); // CHECK:STDOUT: +// CHECK:STDOUT: fn @E(); +// CHECK:STDOUT: // CHECK:STDOUT: fn @__global_init() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %A.ref: = name_ref A, file.%import_ref.1 [template = imports.%A] @@ -263,6 +363,10 @@ import library "extern_api"; // CHECK:STDOUT: %D.ref: = name_ref D, file.%import_ref.4 [template = imports.%D] // CHECK:STDOUT: %.loc9: init () = call %D.ref() // CHECK:STDOUT: assign file.%d.var, %.loc9 +// CHECK:STDOUT: %NS.ref: = name_ref NS, file.%NS [template = file.%NS] +// CHECK:STDOUT: %E.ref: = name_ref E, file.%import_ref.6 [template = imports.%E] +// CHECK:STDOUT: %.loc10: init () = call %E.ref() +// CHECK:STDOUT: assign file.%e.var, %.loc10 // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: @@ -283,15 +387,22 @@ import library "extern_api"; // CHECK:STDOUT: .B = %import_ref.2 // CHECK:STDOUT: .C = %import_ref.3 // CHECK:STDOUT: .D = %import_ref.4 +// CHECK:STDOUT: .NS = %NS // CHECK:STDOUT: .a = %a -// CHECK:STDOUT: .b = %b.loc12 -// CHECK:STDOUT: .c = %c.loc13 +// CHECK:STDOUT: .b = %b.loc13 +// CHECK:STDOUT: .c = %c.loc14 // CHECK:STDOUT: .d = %d +// CHECK:STDOUT: .e = %e // CHECK:STDOUT: } -// CHECK:STDOUT: %import_ref.1: = import_ref ir1, inst+1, loc_11 [template = imports.%A] -// CHECK:STDOUT: %import_ref.2: = import_ref ir1, inst+5, loc_17 [template = imports.%B] -// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+17, loc_28 [template = imports.%C] -// CHECK:STDOUT: %import_ref.4: = import_ref ir1, inst+18, loc_47 [template = imports.%D] +// CHECK:STDOUT: %import_ref.1: = import_ref ir1, inst+1, loc_65 [template = imports.%A] +// CHECK:STDOUT: %import_ref.2: = import_ref ir1, inst+5, loc_74 [template = imports.%B] +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+17, loc_89 [template = imports.%C] +// CHECK:STDOUT: %import_ref.4: = import_ref ir1, inst+18, loc_103 [template = imports.%D] +// CHECK:STDOUT: %import_ref.5: = import_ref ir1, inst+19, loaded +// CHECK:STDOUT: %NS: = namespace %import_ref.5, [template] { +// CHECK:STDOUT: .E = %import_ref.6 +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.6: = import_ref ir1, inst+20, loc_115 [template = imports.%E] // CHECK:STDOUT: %A: = fn_decl @A [template] {} // CHECK:STDOUT: %B: = fn_decl @B [template] { // CHECK:STDOUT: %b.loc7_13.1: i32 = param b @@ -307,19 +418,24 @@ import library "extern_api"; // CHECK:STDOUT: %return.var.loc8: ref {.c: i32} = var // CHECK:STDOUT: } // CHECK:STDOUT: %D: = fn_decl @D [template] {} -// CHECK:STDOUT: %.loc11_9.1: () = tuple_literal () -// CHECK:STDOUT: %.loc11_9.2: type = converted %.loc11_9.1, constants.%.4 [template = constants.%.4] +// CHECK:STDOUT: %E: = fn_decl @E [template] {} +// CHECK:STDOUT: %.loc12_9.1: () = tuple_literal () +// CHECK:STDOUT: %.loc12_9.2: type = converted %.loc12_9.1, constants.%.4 [template = constants.%.4] // CHECK:STDOUT: %a.var: ref () = var a // CHECK:STDOUT: %a: ref () = bind_name a, %a.var // CHECK:STDOUT: %b.var: ref i32 = var b -// CHECK:STDOUT: %b.loc12: ref i32 = bind_name b, %b.var -// CHECK:STDOUT: %.loc13: type = struct_type {.c: i32} [template = constants.%.3] +// CHECK:STDOUT: %b.loc13: ref i32 = bind_name b, %b.var +// CHECK:STDOUT: %.loc14: type = struct_type {.c: i32} [template = constants.%.3] // CHECK:STDOUT: %c.var: ref {.c: i32} = var c -// CHECK:STDOUT: %c.loc13: ref {.c: i32} = bind_name c, %c.var -// CHECK:STDOUT: %.loc14_9.1: () = tuple_literal () -// CHECK:STDOUT: %.loc14_9.2: type = converted %.loc14_9.1, constants.%.4 [template = constants.%.4] +// CHECK:STDOUT: %c.loc14: ref {.c: i32} = bind_name c, %c.var +// CHECK:STDOUT: %.loc15_9.1: () = tuple_literal () +// CHECK:STDOUT: %.loc15_9.2: type = converted %.loc15_9.1, constants.%.4 [template = constants.%.4] // CHECK:STDOUT: %d.var: ref () = var d // CHECK:STDOUT: %d: ref () = bind_name d, %d.var +// CHECK:STDOUT: %.loc16_9.1: () = tuple_literal () +// CHECK:STDOUT: %.loc16_9.2: type = converted %.loc16_9.1, constants.%.4 [template = constants.%.4] +// CHECK:STDOUT: %e.var: ref () = var e +// CHECK:STDOUT: %e: ref () = bind_name e, %e.var // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @A(); @@ -330,25 +446,31 @@ import library "extern_api"; // CHECK:STDOUT: // CHECK:STDOUT: extern fn @D(); // CHECK:STDOUT: +// CHECK:STDOUT: fn @E(); +// CHECK:STDOUT: // CHECK:STDOUT: fn @__global_init() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %A.ref: = name_ref A, file.%import_ref.1 [template = imports.%A] -// CHECK:STDOUT: %.loc11: init () = call %A.ref() -// CHECK:STDOUT: assign file.%a.var, %.loc11 +// CHECK:STDOUT: %.loc12: init () = call %A.ref() +// CHECK:STDOUT: assign file.%a.var, %.loc12 // CHECK:STDOUT: %B.ref: = name_ref B, file.%import_ref.2 [template = imports.%B] -// CHECK:STDOUT: %.loc12_16: i32 = int_literal 1 [template = constants.%.5] -// CHECK:STDOUT: %.loc12_15: init i32 = call %B.ref(%.loc12_16) -// CHECK:STDOUT: assign file.%b.var, %.loc12_15 +// CHECK:STDOUT: %.loc13_16: i32 = int_literal 1 [template = constants.%.5] +// CHECK:STDOUT: %.loc13_15: init i32 = call %B.ref(%.loc13_16) +// CHECK:STDOUT: assign file.%b.var, %.loc13_15 // CHECK:STDOUT: %C.ref: = name_ref C, file.%import_ref.3 [template = imports.%C] -// CHECK:STDOUT: %.loc13_23: i32 = int_literal 1 [template = constants.%.5] -// CHECK:STDOUT: %.loc13_25.1: (i32,) = tuple_literal (%.loc13_23) -// CHECK:STDOUT: %.loc13_25.2: (i32,) = tuple_value (%.loc13_23) [template = constants.%.6] -// CHECK:STDOUT: %.loc13_25.3: (i32,) = converted %.loc13_25.1, %.loc13_25.2 [template = constants.%.6] -// CHECK:STDOUT: %.loc13_21: init {.c: i32} = call %C.ref(%.loc13_25.3) -// CHECK:STDOUT: assign file.%c.var, %.loc13_21 +// CHECK:STDOUT: %.loc14_23: i32 = int_literal 1 [template = constants.%.5] +// CHECK:STDOUT: %.loc14_25.1: (i32,) = tuple_literal (%.loc14_23) +// CHECK:STDOUT: %.loc14_25.2: (i32,) = tuple_value (%.loc14_23) [template = constants.%.6] +// CHECK:STDOUT: %.loc14_25.3: (i32,) = converted %.loc14_25.1, %.loc14_25.2 [template = constants.%.6] +// CHECK:STDOUT: %.loc14_21: init {.c: i32} = call %C.ref(%.loc14_25.3) +// CHECK:STDOUT: assign file.%c.var, %.loc14_21 // CHECK:STDOUT: %D.ref: = name_ref D, file.%import_ref.4 [template = imports.%D] -// CHECK:STDOUT: %.loc14: init () = call %D.ref() -// CHECK:STDOUT: assign file.%d.var, %.loc14 +// CHECK:STDOUT: %.loc15: init () = call %D.ref() +// CHECK:STDOUT: assign file.%d.var, %.loc15 +// CHECK:STDOUT: %NS.ref: = name_ref NS, file.%NS [template = file.%NS] +// CHECK:STDOUT: %E.ref: = name_ref E, file.%import_ref.6 [template = imports.%E] +// CHECK:STDOUT: %.loc16: init () = call %E.ref() +// CHECK:STDOUT: assign file.%e.var, %.loc16 // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: @@ -369,15 +491,22 @@ import library "extern_api"; // CHECK:STDOUT: .B = %import_ref.2 // CHECK:STDOUT: .C = %import_ref.3 // CHECK:STDOUT: .D = %import_ref.4 +// CHECK:STDOUT: .NS = %NS // CHECK:STDOUT: .a = %a -// CHECK:STDOUT: .b = %b.loc12 -// CHECK:STDOUT: .c = %c.loc13 +// CHECK:STDOUT: .b = %b.loc13 +// CHECK:STDOUT: .c = %c.loc14 // CHECK:STDOUT: .d = %d +// CHECK:STDOUT: .e = %e // CHECK:STDOUT: } -// CHECK:STDOUT: %import_ref.1: = import_ref ir1, inst+1, loc_11 [template = imports.%A] -// CHECK:STDOUT: %import_ref.2: = import_ref ir1, inst+5, loc_17 [template = imports.%B] -// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+17, loc_28 [template = imports.%C] -// CHECK:STDOUT: %import_ref.4: = import_ref ir1, inst+18, loc_47 [template = imports.%D] +// CHECK:STDOUT: %import_ref.1: = import_ref ir1, inst+1, loc_65 [template = imports.%A] +// CHECK:STDOUT: %import_ref.2: = import_ref ir1, inst+5, loc_74 [template = imports.%B] +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+17, loc_89 [template = imports.%C] +// CHECK:STDOUT: %import_ref.4: = import_ref ir1, inst+18, loc_103 [template = imports.%D] +// CHECK:STDOUT: %import_ref.5: = import_ref ir1, inst+19, loaded +// CHECK:STDOUT: %NS: = namespace %import_ref.5, [template] { +// CHECK:STDOUT: .E = %import_ref.6 +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.6: = import_ref ir1, inst+20, loc_115 [template = imports.%E] // CHECK:STDOUT: %A: = fn_decl @A [template] {} // CHECK:STDOUT: %B: = fn_decl @B [template] { // CHECK:STDOUT: %b.loc7_13.1: i32 = param b @@ -393,19 +522,24 @@ import library "extern_api"; // CHECK:STDOUT: %return.var.loc8: ref {.c: i32} = var // CHECK:STDOUT: } // CHECK:STDOUT: %D: = fn_decl @D [template] {} -// CHECK:STDOUT: %.loc11_9.1: () = tuple_literal () -// CHECK:STDOUT: %.loc11_9.2: type = converted %.loc11_9.1, constants.%.4 [template = constants.%.4] +// CHECK:STDOUT: %E: = fn_decl @E [template] {} +// CHECK:STDOUT: %.loc12_9.1: () = tuple_literal () +// CHECK:STDOUT: %.loc12_9.2: type = converted %.loc12_9.1, constants.%.4 [template = constants.%.4] // CHECK:STDOUT: %a.var: ref () = var a // CHECK:STDOUT: %a: ref () = bind_name a, %a.var // CHECK:STDOUT: %b.var: ref i32 = var b -// CHECK:STDOUT: %b.loc12: ref i32 = bind_name b, %b.var -// CHECK:STDOUT: %.loc13: type = struct_type {.c: i32} [template = constants.%.3] +// CHECK:STDOUT: %b.loc13: ref i32 = bind_name b, %b.var +// CHECK:STDOUT: %.loc14: type = struct_type {.c: i32} [template = constants.%.3] // CHECK:STDOUT: %c.var: ref {.c: i32} = var c -// CHECK:STDOUT: %c.loc13: ref {.c: i32} = bind_name c, %c.var -// CHECK:STDOUT: %.loc14_9.1: () = tuple_literal () -// CHECK:STDOUT: %.loc14_9.2: type = converted %.loc14_9.1, constants.%.4 [template = constants.%.4] +// CHECK:STDOUT: %c.loc14: ref {.c: i32} = bind_name c, %c.var +// CHECK:STDOUT: %.loc15_9.1: () = tuple_literal () +// CHECK:STDOUT: %.loc15_9.2: type = converted %.loc15_9.1, constants.%.4 [template = constants.%.4] // CHECK:STDOUT: %d.var: ref () = var d // CHECK:STDOUT: %d: ref () = bind_name d, %d.var +// CHECK:STDOUT: %.loc16_9.1: () = tuple_literal () +// CHECK:STDOUT: %.loc16_9.2: type = converted %.loc16_9.1, constants.%.4 [template = constants.%.4] +// CHECK:STDOUT: %e.var: ref () = var e +// CHECK:STDOUT: %e: ref () = bind_name e, %e.var // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: extern fn @A(); @@ -416,25 +550,31 @@ import library "extern_api"; // CHECK:STDOUT: // CHECK:STDOUT: extern fn @D(); // CHECK:STDOUT: +// CHECK:STDOUT: extern fn @E(); +// CHECK:STDOUT: // CHECK:STDOUT: fn @__global_init() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %A.ref: = name_ref A, file.%import_ref.1 [template = imports.%A] -// CHECK:STDOUT: %.loc11: init () = call %A.ref() -// CHECK:STDOUT: assign file.%a.var, %.loc11 +// CHECK:STDOUT: %.loc12: init () = call %A.ref() +// CHECK:STDOUT: assign file.%a.var, %.loc12 // CHECK:STDOUT: %B.ref: = name_ref B, file.%import_ref.2 [template = imports.%B] -// CHECK:STDOUT: %.loc12_16: i32 = int_literal 1 [template = constants.%.5] -// CHECK:STDOUT: %.loc12_15: init i32 = call %B.ref(%.loc12_16) -// CHECK:STDOUT: assign file.%b.var, %.loc12_15 +// CHECK:STDOUT: %.loc13_16: i32 = int_literal 1 [template = constants.%.5] +// CHECK:STDOUT: %.loc13_15: init i32 = call %B.ref(%.loc13_16) +// CHECK:STDOUT: assign file.%b.var, %.loc13_15 // CHECK:STDOUT: %C.ref: = name_ref C, file.%import_ref.3 [template = imports.%C] -// CHECK:STDOUT: %.loc13_23: i32 = int_literal 1 [template = constants.%.5] -// CHECK:STDOUT: %.loc13_25.1: (i32,) = tuple_literal (%.loc13_23) -// CHECK:STDOUT: %.loc13_25.2: (i32,) = tuple_value (%.loc13_23) [template = constants.%.6] -// CHECK:STDOUT: %.loc13_25.3: (i32,) = converted %.loc13_25.1, %.loc13_25.2 [template = constants.%.6] -// CHECK:STDOUT: %.loc13_21: init {.c: i32} = call %C.ref(%.loc13_25.3) -// CHECK:STDOUT: assign file.%c.var, %.loc13_21 +// CHECK:STDOUT: %.loc14_23: i32 = int_literal 1 [template = constants.%.5] +// CHECK:STDOUT: %.loc14_25.1: (i32,) = tuple_literal (%.loc14_23) +// CHECK:STDOUT: %.loc14_25.2: (i32,) = tuple_value (%.loc14_23) [template = constants.%.6] +// CHECK:STDOUT: %.loc14_25.3: (i32,) = converted %.loc14_25.1, %.loc14_25.2 [template = constants.%.6] +// CHECK:STDOUT: %.loc14_21: init {.c: i32} = call %C.ref(%.loc14_25.3) +// CHECK:STDOUT: assign file.%c.var, %.loc14_21 // CHECK:STDOUT: %D.ref: = name_ref D, file.%import_ref.4 [template = imports.%D] -// CHECK:STDOUT: %.loc14: init () = call %D.ref() -// CHECK:STDOUT: assign file.%d.var, %.loc14 +// CHECK:STDOUT: %.loc15: init () = call %D.ref() +// CHECK:STDOUT: assign file.%d.var, %.loc15 +// CHECK:STDOUT: %NS.ref: = name_ref NS, file.%NS [template = file.%NS] +// CHECK:STDOUT: %E.ref: = name_ref E, file.%import_ref.6 [template = imports.%E] +// CHECK:STDOUT: %.loc16: init () = call %E.ref() +// CHECK:STDOUT: assign file.%e.var, %.loc16 // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: @@ -454,19 +594,27 @@ import library "extern_api"; // CHECK:STDOUT: .B = %import_ref.2 // CHECK:STDOUT: .C = %import_ref.3 // CHECK:STDOUT: .D = %import_ref.4 +// CHECK:STDOUT: .NS = %NS // CHECK:STDOUT: .a = %a // CHECK:STDOUT: .b = %b // CHECK:STDOUT: .c = %c // CHECK:STDOUT: .d = %d +// CHECK:STDOUT: .e = %e // CHECK:STDOUT: } // CHECK:STDOUT: %import_ref.1: = import_ref ir1, inst+1, loc_19 [template = imports.%A.1] // CHECK:STDOUT: %import_ref.2: = import_ref ir1, inst+5, loc_28 [template = imports.%B.1] // CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+17, loc_43 [template = imports.%C.1] // CHECK:STDOUT: %import_ref.4: = import_ref ir1, inst+18, loc_57 [template = imports.%D.1] -// CHECK:STDOUT: %import_ref.5: = import_ref ir2, inst+1, loaded [template = imports.%A.2] -// CHECK:STDOUT: %import_ref.6: = import_ref ir2, inst+5, loaded [template = imports.%B.2] -// CHECK:STDOUT: %import_ref.7: = import_ref ir2, inst+17, loaded [template = imports.%C.2] -// CHECK:STDOUT: %import_ref.8: = import_ref ir2, inst+18, loaded [template = imports.%D.2] +// CHECK:STDOUT: %import_ref.5: = import_ref ir1, inst+19, loaded +// CHECK:STDOUT: %NS: = namespace %import_ref.5, [template] { +// CHECK:STDOUT: .E = %import_ref.6 +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.6: = import_ref ir1, inst+20, loc_69 [template = imports.%E.1] +// CHECK:STDOUT: %import_ref.7: = import_ref ir2, inst+1, loaded [template = imports.%A.2] +// CHECK:STDOUT: %import_ref.8: = import_ref ir2, inst+5, loaded [template = imports.%B.2] +// CHECK:STDOUT: %import_ref.9: = import_ref ir2, inst+17, loaded [template = imports.%C.2] +// CHECK:STDOUT: %import_ref.10: = import_ref ir2, inst+18, loaded [template = imports.%D.2] +// CHECK:STDOUT: %import_ref.11: = import_ref ir2, inst+20, loaded [template = imports.%E.2] // CHECK:STDOUT: %.loc7_9.1: () = tuple_literal () // CHECK:STDOUT: %.loc7_9.2: type = converted %.loc7_9.1, constants.%.3 [template = constants.%.3] // CHECK:STDOUT: %a.var: ref () = var a @@ -480,6 +628,10 @@ import library "extern_api"; // CHECK:STDOUT: %.loc10_9.2: type = converted %.loc10_9.1, constants.%.3 [template = constants.%.3] // CHECK:STDOUT: %d.var: ref () = var d // CHECK:STDOUT: %d: ref () = bind_name d, %d.var +// CHECK:STDOUT: %.loc11_9.1: () = tuple_literal () +// CHECK:STDOUT: %.loc11_9.2: type = converted %.loc11_9.1, constants.%.3 [template = constants.%.3] +// CHECK:STDOUT: %e.var: ref () = var e +// CHECK:STDOUT: %e: ref () = bind_name e, %e.var // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: extern fn @A.1(); @@ -498,6 +650,10 @@ import library "extern_api"; // CHECK:STDOUT: // CHECK:STDOUT: extern fn @D.2(); // CHECK:STDOUT: +// CHECK:STDOUT: extern fn @E.1(); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @E.2(); +// CHECK:STDOUT: // CHECK:STDOUT: fn @__global_init() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %A.ref: = name_ref A, file.%import_ref.1 [template = imports.%A.1] @@ -517,6 +673,10 @@ import library "extern_api"; // CHECK:STDOUT: %D.ref: = name_ref D, file.%import_ref.4 [template = imports.%D.1] // CHECK:STDOUT: %.loc10: init () = call %D.ref() // CHECK:STDOUT: assign file.%d.var, %.loc10 +// CHECK:STDOUT: %NS.ref: = name_ref NS, file.%NS [template = file.%NS] +// CHECK:STDOUT: %E.ref: = name_ref E, file.%import_ref.6 [template = imports.%E.1] +// CHECK:STDOUT: %.loc11: init () = call %E.ref() +// CHECK:STDOUT: assign file.%e.var, %.loc11 // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: @@ -536,19 +696,27 @@ import library "extern_api"; // CHECK:STDOUT: .B = %import_ref.2 // CHECK:STDOUT: .C = %import_ref.3 // CHECK:STDOUT: .D = %import_ref.4 +// CHECK:STDOUT: .NS = %NS // CHECK:STDOUT: .a = %a // CHECK:STDOUT: .b = %b // CHECK:STDOUT: .c = %c // CHECK:STDOUT: .d = %d +// CHECK:STDOUT: .e = %e // CHECK:STDOUT: } // CHECK:STDOUT: %import_ref.1: = import_ref ir1, inst+1, loc_19 [template = imports.%A.1] // CHECK:STDOUT: %import_ref.2: = import_ref ir1, inst+5, loc_28 [template = imports.%B.1] // CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+17, loc_43 [template = imports.%C.1] // CHECK:STDOUT: %import_ref.4: = import_ref ir1, inst+18, loc_57 [template = imports.%D.1] -// CHECK:STDOUT: %import_ref.5: = import_ref ir2, inst+1, loaded [template = imports.%A.2] -// CHECK:STDOUT: %import_ref.6: = import_ref ir2, inst+5, loaded [template = imports.%B.2] -// CHECK:STDOUT: %import_ref.7: = import_ref ir2, inst+17, loaded [template = imports.%C.2] -// CHECK:STDOUT: %import_ref.8: = import_ref ir2, inst+18, loaded [template = imports.%D.2] +// CHECK:STDOUT: %import_ref.5: = import_ref ir1, inst+19, loaded +// CHECK:STDOUT: %NS: = namespace %import_ref.5, [template] { +// CHECK:STDOUT: .E = %import_ref.6 +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.6: = import_ref ir1, inst+20, loc_69 [template = imports.%E.1] +// CHECK:STDOUT: %import_ref.7: = import_ref ir2, inst+1, loaded [template = imports.%A.2] +// CHECK:STDOUT: %import_ref.8: = import_ref ir2, inst+5, loaded [template = imports.%B.2] +// CHECK:STDOUT: %import_ref.9: = import_ref ir2, inst+17, loaded [template = imports.%C.2] +// CHECK:STDOUT: %import_ref.10: = import_ref ir2, inst+18, loaded [template = imports.%D.2] +// CHECK:STDOUT: %import_ref.11: = import_ref ir2, inst+20, loaded [template = imports.%E.2] // CHECK:STDOUT: %.loc7_9.1: () = tuple_literal () // CHECK:STDOUT: %.loc7_9.2: type = converted %.loc7_9.1, constants.%.3 [template = constants.%.3] // CHECK:STDOUT: %a.var: ref () = var a @@ -562,6 +730,10 @@ import library "extern_api"; // CHECK:STDOUT: %.loc10_9.2: type = converted %.loc10_9.1, constants.%.3 [template = constants.%.3] // CHECK:STDOUT: %d.var: ref () = var d // CHECK:STDOUT: %d: ref () = bind_name d, %d.var +// CHECK:STDOUT: %.loc11_9.1: () = tuple_literal () +// CHECK:STDOUT: %.loc11_9.2: type = converted %.loc11_9.1, constants.%.3 [template = constants.%.3] +// CHECK:STDOUT: %e.var: ref () = var e +// CHECK:STDOUT: %e: ref () = bind_name e, %e.var // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @A.1(); @@ -580,6 +752,10 @@ import library "extern_api"; // CHECK:STDOUT: // CHECK:STDOUT: extern fn @D.2(); // CHECK:STDOUT: +// CHECK:STDOUT: fn @E.1(); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @E.2(); +// CHECK:STDOUT: // CHECK:STDOUT: fn @__global_init() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %A.ref: = name_ref A, file.%import_ref.1 [template = imports.%A.1] @@ -599,6 +775,137 @@ import library "extern_api"; // CHECK:STDOUT: %D.ref: = name_ref D, file.%import_ref.4 [template = imports.%D.1] // CHECK:STDOUT: %.loc10: init () = call %D.ref() // CHECK:STDOUT: assign file.%d.var, %.loc10 +// CHECK:STDOUT: %NS.ref: = name_ref NS, file.%NS [template = file.%NS] +// CHECK:STDOUT: %E.ref: = name_ref E, file.%import_ref.6 [template = imports.%E.1] +// CHECK:STDOUT: %.loc11: init () = call %E.ref() +// CHECK:STDOUT: assign file.%e.var, %.loc11 +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_decl_after_use.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .A = %import_ref.1 +// CHECK:STDOUT: .B = %import_ref.2 +// CHECK:STDOUT: .C = %import_ref.3 +// CHECK:STDOUT: .D = %import_ref.4 +// CHECK:STDOUT: .NS = %NS +// CHECK:STDOUT: .a = %a +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.1: = import_ref ir1, inst+1, loc_15 [template = imports.%A] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+5, unloaded +// CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+17, unloaded +// CHECK:STDOUT: %import_ref.4 = import_ref ir1, inst+18, unloaded +// CHECK:STDOUT: %import_ref.5: = import_ref ir1, inst+19, loaded +// CHECK:STDOUT: %NS: = namespace %import_ref.5, [template] { +// CHECK:STDOUT: .E = %import_ref.6 +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.6 = import_ref ir1, inst+20, unloaded +// CHECK:STDOUT: %.loc6_9.1: () = tuple_literal () +// CHECK:STDOUT: %.loc6_9.2: type = converted %.loc6_9.1, constants.%.1 [template = constants.%.1] +// CHECK:STDOUT: %a.var: ref () = var a +// CHECK:STDOUT: %a: ref () = bind_name a, %a.var +// CHECK:STDOUT: %A: = fn_decl @A [template] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @A(); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @__global_init() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %A.ref: = name_ref A, file.%import_ref.1 [template = imports.%A] +// CHECK:STDOUT: %.loc6: init () = call %A.ref() +// CHECK:STDOUT: assign file.%a.var, %.loc6 +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_decl_after_use_two_errors.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .A = %import_ref.1 +// CHECK:STDOUT: .B = %import_ref.2 +// CHECK:STDOUT: .C = %import_ref.3 +// CHECK:STDOUT: .D = %import_ref.4 +// CHECK:STDOUT: .NS = %NS +// CHECK:STDOUT: .a = %a +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.1: = import_ref ir1, inst+1, loc_15 [template = imports.%A] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+5, unloaded +// CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+17, unloaded +// CHECK:STDOUT: %import_ref.4 = import_ref ir1, inst+18, unloaded +// CHECK:STDOUT: %import_ref.5: = import_ref ir1, inst+19, loaded +// CHECK:STDOUT: %NS: = namespace %import_ref.5, [template] { +// CHECK:STDOUT: .E = %import_ref.6 +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.6 = import_ref ir1, inst+20, unloaded +// CHECK:STDOUT: %.loc6_9.1: () = tuple_literal () +// CHECK:STDOUT: %.loc6_9.2: type = converted %.loc6_9.1, constants.%.1 [template = constants.%.1] +// CHECK:STDOUT: %a.var: ref () = var a +// CHECK:STDOUT: %a: ref () = bind_name a, %a.var +// CHECK:STDOUT: %.loc25: = fn_decl @.1 [template] { +// CHECK:STDOUT: %return.var: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: extern fn @A(); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @.1() -> i32; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @__global_init() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %A.ref: = name_ref A, file.%import_ref.1 [template = imports.%A] +// CHECK:STDOUT: %.loc6: init () = call %A.ref() +// CHECK:STDOUT: assign file.%a.var, %.loc6 +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_extern_after_use.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .A = %import_ref.1 +// CHECK:STDOUT: .B = %import_ref.2 +// CHECK:STDOUT: .C = %import_ref.3 +// CHECK:STDOUT: .D = %import_ref.4 +// CHECK:STDOUT: .NS = %NS +// CHECK:STDOUT: .a = %a +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.1: = import_ref ir1, inst+1, loc_15 [template = imports.%A] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+5, unloaded +// CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+17, unloaded +// CHECK:STDOUT: %import_ref.4 = import_ref ir1, inst+18, unloaded +// CHECK:STDOUT: %import_ref.5: = import_ref ir1, inst+19, loaded +// CHECK:STDOUT: %NS: = namespace %import_ref.5, [template] { +// CHECK:STDOUT: .E = %import_ref.6 +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.6 = import_ref ir1, inst+20, unloaded +// CHECK:STDOUT: %.loc6_9.1: () = tuple_literal () +// CHECK:STDOUT: %.loc6_9.2: type = converted %.loc6_9.1, constants.%.1 [template = constants.%.1] +// CHECK:STDOUT: %a.var: ref () = var a +// CHECK:STDOUT: %a: ref () = bind_name a, %a.var +// CHECK:STDOUT: %A: = fn_decl @A [template] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @A(); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @__global_init() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %A.ref: = name_ref A, file.%import_ref.1 [template = imports.%A] +// CHECK:STDOUT: %.loc6: init () = call %A.ref() +// CHECK:STDOUT: assign file.%a.var, %.loc6 // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: @@ -610,11 +917,17 @@ import library "extern_api"; // CHECK:STDOUT: .B = %import_ref.2 // CHECK:STDOUT: .C = %import_ref.3 // CHECK:STDOUT: .D = %import_ref.4 +// CHECK:STDOUT: .NS = %NS // CHECK:STDOUT: } // CHECK:STDOUT: %import_ref.1 = import_ref ir1, inst+1, unloaded // CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+5, unloaded // CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+17, unloaded // CHECK:STDOUT: %import_ref.4 = import_ref ir1, inst+18, unloaded +// CHECK:STDOUT: %import_ref.5: = import_ref ir1, inst+19, loaded +// CHECK:STDOUT: %NS: = namespace %import_ref.5, [template] { +// CHECK:STDOUT: .E = %import_ref.6 +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.6 = import_ref ir1, inst+20, unloaded // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- unloaded_extern.carbon @@ -625,11 +938,17 @@ import library "extern_api"; // CHECK:STDOUT: .B = %import_ref.2 // CHECK:STDOUT: .C = %import_ref.3 // CHECK:STDOUT: .D = %import_ref.4 +// CHECK:STDOUT: .NS = %NS // CHECK:STDOUT: } // CHECK:STDOUT: %import_ref.1 = import_ref ir1, inst+1, unloaded // CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+5, unloaded // CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+17, unloaded // CHECK:STDOUT: %import_ref.4 = import_ref ir1, inst+18, unloaded +// CHECK:STDOUT: %import_ref.5: = import_ref ir1, inst+19, loaded +// CHECK:STDOUT: %NS: = namespace %import_ref.5, [template] { +// CHECK:STDOUT: .E = %import_ref.6 +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.6 = import_ref ir1, inst+20, unloaded // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- loaded_merge.carbon @@ -645,15 +964,22 @@ import library "extern_api"; // CHECK:STDOUT: .B = %import_ref.2 // CHECK:STDOUT: .C = %import_ref.3 // CHECK:STDOUT: .D = %import_ref.4 +// CHECK:STDOUT: .NS = %NS // CHECK:STDOUT: } // CHECK:STDOUT: %import_ref.1: = import_ref ir1, inst+1, loaded [template = imports.%A.1] // CHECK:STDOUT: %import_ref.2: = import_ref ir1, inst+5, loaded [template = imports.%B.1] // CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+17, loaded [template = imports.%C.1] // CHECK:STDOUT: %import_ref.4: = import_ref ir1, inst+18, loaded [template = imports.%D.1] -// CHECK:STDOUT: %import_ref.5: = import_ref ir2, inst+1, loaded [template = imports.%A.2] -// CHECK:STDOUT: %import_ref.6: = import_ref ir2, inst+5, loaded [template = imports.%B.2] -// CHECK:STDOUT: %import_ref.7: = import_ref ir2, inst+17, loaded [template = imports.%C.2] -// CHECK:STDOUT: %import_ref.8: = import_ref ir2, inst+18, loaded [template = imports.%D.2] +// CHECK:STDOUT: %import_ref.5: = import_ref ir1, inst+19, loaded +// CHECK:STDOUT: %NS: = namespace %import_ref.5, [template] { +// CHECK:STDOUT: .E = %import_ref.6 +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.6: = import_ref ir1, inst+20, loaded [template = imports.%E.1] +// CHECK:STDOUT: %import_ref.7: = import_ref ir2, inst+1, loaded [template = imports.%A.2] +// CHECK:STDOUT: %import_ref.8: = import_ref ir2, inst+5, loaded [template = imports.%B.2] +// CHECK:STDOUT: %import_ref.9: = import_ref ir2, inst+17, loaded [template = imports.%C.2] +// CHECK:STDOUT: %import_ref.10: = import_ref ir2, inst+18, loaded [template = imports.%D.2] +// CHECK:STDOUT: %import_ref.11: = import_ref ir2, inst+20, loaded [template = imports.%E.2] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: extern fn @A.1(); @@ -672,3 +998,7 @@ import library "extern_api"; // CHECK:STDOUT: // CHECK:STDOUT: extern fn @D.2(); // CHECK:STDOUT: +// CHECK:STDOUT: extern fn @E.1(); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @E.2(); +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/definition/import.carbon b/toolchain/check/testdata/function/definition/import.carbon index 2909ffd87e84..569385a8617d 100644 --- a/toolchain/check/testdata/function/definition/import.carbon +++ b/toolchain/check/testdata/function/definition/import.carbon @@ -204,8 +204,8 @@ fn D() {} // CHECK:STDOUT: .C = %import_ref.3 // CHECK:STDOUT: .D = %import_ref.4 // CHECK:STDOUT: } -// CHECK:STDOUT: %import_ref.1: = import_ref ir1, inst+1, loc_10 [template = imports.%A] -// CHECK:STDOUT: %import_ref.2: = import_ref ir1, inst+6, loc_17 [template = imports.%B] +// CHECK:STDOUT: %import_ref.1: = import_ref ir1, inst+1, loaded [template = imports.%A] +// CHECK:STDOUT: %import_ref.2: = import_ref ir1, inst+6, loaded [template = imports.%B] // CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+20, unloaded // CHECK:STDOUT: %import_ref.4 = import_ref ir1, inst+30, unloaded // CHECK:STDOUT: %A: = fn_decl @A [template] {} @@ -235,7 +235,7 @@ fn D() {} // CHECK:STDOUT: %import_ref.1 = import_ref ir1, inst+1, unloaded // CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+6, unloaded // CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+20, unloaded -// CHECK:STDOUT: %import_ref.4: = import_ref ir1, inst+30, loc_11 [template = imports.%D] +// CHECK:STDOUT: %import_ref.4: = import_ref ir1, inst+30, loaded [template = imports.%D] // CHECK:STDOUT: %D.loc6: = fn_decl @D [template] {} // CHECK:STDOUT: %D.loc16: = fn_decl @D [template] {} // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/namespace/fail_conflict_imported_namespace_second.carbon b/toolchain/check/testdata/namespace/fail_conflict_imported_namespace_second.carbon index f3c003a26cc4..5f3cd091470a 100644 --- a/toolchain/check/testdata/namespace/fail_conflict_imported_namespace_second.carbon +++ b/toolchain/check/testdata/namespace/fail_conflict_imported_namespace_second.carbon @@ -53,7 +53,7 @@ fn NS.Foo(); // CHECK:STDOUT: package: = namespace [template] { // CHECK:STDOUT: .NS = %import_ref // CHECK:STDOUT: } -// CHECK:STDOUT: %import_ref: = import_ref ir1, inst+1, loc_10 [template = imports.%NS] +// CHECK:STDOUT: %import_ref: = import_ref ir1, inst+1, loaded [template = imports.%NS] // CHECK:STDOUT: %.loc16: = namespace [template] {} // CHECK:STDOUT: %.loc24: = fn_decl @.1 [template] {} // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/packages/cross_package_import.carbon b/toolchain/check/testdata/packages/cross_package_import.carbon index 6239f3531b12..caab735530cd 100644 --- a/toolchain/check/testdata/packages/cross_package_import.carbon +++ b/toolchain/check/testdata/packages/cross_package_import.carbon @@ -332,7 +332,7 @@ fn Other.G() {} // CHECK:STDOUT: } // CHECK:STDOUT: %import_ref.1: = import_ref ir1, inst+1, loaded // CHECK:STDOUT: %Other: = namespace %import_ref.1, [template] {} -// CHECK:STDOUT: %import_ref.2: = import_ref ir2, inst+1, loc_16 [template = imports.%F] +// CHECK:STDOUT: %import_ref.2: = import_ref ir2, inst+1, loaded [template = imports.%F] // CHECK:STDOUT: %F: = fn_decl @F [template] {} // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/diagnostics/diagnostic_kind.def b/toolchain/diagnostics/diagnostic_kind.def index 88ad19cb9d40..2183574dbf41 100644 --- a/toolchain/diagnostics/diagnostic_kind.def +++ b/toolchain/diagnostics/diagnostic_kind.def @@ -148,6 +148,8 @@ CARBON_DIAGNOSTIC_KIND(ImportSelf) CARBON_DIAGNOSTIC_KIND(ExplicitImportApi) CARBON_DIAGNOSTIC_KIND(RepeatedImport) CARBON_DIAGNOSTIC_KIND(FirstImported) +CARBON_DIAGNOSTIC_KIND(RedeclOfUsedImport) +CARBON_DIAGNOSTIC_KIND(UsedImportLoc) // Function call checking. CARBON_DIAGNOSTIC_KIND(AddrSelfIsNonRef)