diff --git a/toolchain/check/check.cpp b/toolchain/check/check.cpp index 9fbe96cac4e0..3506cd3125fe 100644 --- a/toolchain/check/check.cpp +++ b/toolchain/check/check.cpp @@ -52,7 +52,7 @@ class SemIRLocationTranslator // If the parse node was invalid, recurse through import references when // possible. - if (auto import_ref = cursor_ir->insts().TryGetAs( + if (auto import_ref = cursor_ir->insts().TryGetAs( cursor_inst_id)) { cursor_ir = cursor_ir->cross_ref_irs().Get(import_ref->ir_id); cursor_inst_id = import_ref->inst_id; diff --git a/toolchain/check/context.cpp b/toolchain/check/context.cpp index bbd0be38f41b..ffe83eddc1fb 100644 --- a/toolchain/check/context.cpp +++ b/toolchain/check/context.cpp @@ -221,46 +221,26 @@ auto Context::AddNameToLookup(SemIR::NameId name_id, SemIR::InstId target_id) auto Context::ResolveIfImportRefUnused(SemIR::InstId inst_id) -> void { auto inst = insts().Get(inst_id); - auto lazy_inst = inst.TryAs(); - if (!lazy_inst) { + auto unused_inst = inst.TryAs(); + if (!unused_inst) { return; } - const SemIR::File& import_ir = *cross_ref_irs().Get(lazy_inst->ir_id); - auto import_inst = import_ir.insts().Get(lazy_inst->inst_id); + const SemIR::File& import_ir = *cross_ref_irs().Get(unused_inst->ir_id); + auto import_inst = import_ir.insts().Get(unused_inst->inst_id); switch (import_inst.kind()) { - case SemIR::InstKind::FunctionDecl: { - // TODO: Fill this in better. - auto function_id = - functions().Add({.name_id = SemIR::NameId::Invalid, - .enclosing_scope_id = SemIR::NameScopeId::Invalid, - .decl_id = inst_id, - .implicit_param_refs_id = SemIR::InstBlockId::Empty, - .param_refs_id = SemIR::InstBlockId::Empty, - .return_type_id = SemIR::TypeId::Invalid, - .return_slot_id = SemIR::InstId::Invalid}); - ReplaceInstBeforeConstantUse( - inst_id, - // TODO: For diagnostic purposes, we should provide some form of - // location for the function. - {Parse::NodeId::Invalid, - SemIR::FunctionDecl{GetBuiltinType(SemIR::BuiltinKind::FunctionType), - function_id}}); - constant_values().Set(inst_id, - SemIR::ConstantId::ForTemplateConstant(inst_id)); - break; - } - default: // TODO: We need more type support. For now we inject an arbitrary // invalid node that's unrelated to the underlying value. The TODO // diagnostic is used since this section shouldn't typically be able to // error. TODO(Parse::NodeId::Invalid, - (llvm::Twine("TODO: support ") + import_inst.kind().name()).str()); + (llvm::Twine("TODO: ResolveIfImportRefUnused for ") + + import_inst.kind().name()) + .str()); ReplaceInstBeforeConstantUse( - inst_id, {Parse::NodeId::Invalid, - SemIR::VarStorage{SemIR::TypeId::Error, - SemIR::NameId::PackageNamespace}}); + inst_id, + {SemIR::ImportRefUsed{SemIR::TypeId::Error, unused_inst->ir_id, + unused_inst->inst_id}}); break; } } @@ -970,6 +950,7 @@ class TypeCompleter { case SemIR::InterfaceDecl::Kind: case SemIR::IntLiteral::Kind: case SemIR::ImportRefUnused::Kind: + case SemIR::ImportRefUsed::Kind: case SemIR::NameRef::Kind: case SemIR::Namespace::Kind: case SemIR::Param::Kind: diff --git a/toolchain/check/eval.cpp b/toolchain/check/eval.cpp index 42b296aaf654..34ef76c649fe 100644 --- a/toolchain/check/eval.cpp +++ b/toolchain/check/eval.cpp @@ -477,6 +477,7 @@ auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst) case SemIR::ClassDecl::Kind: case SemIR::Import::Kind: case SemIR::ImportRefUnused::Kind: + case SemIR::ImportRefUsed::Kind: case SemIR::InterfaceDecl::Kind: case SemIR::Param::Kind: case SemIR::ReturnExpr::Kind: diff --git a/toolchain/check/import.cpp b/toolchain/check/import.cpp index 99a7da9f4d7b..2ccebf195dc7 100644 --- a/toolchain/check/import.cpp +++ b/toolchain/check/import.cpp @@ -103,8 +103,8 @@ static auto CopySingleNameScopeFromImportIR( } // Produce the namespace for the entry. - auto ref_id = context.AddInst( - SemIR::ImportRefUnused{.ir_id = ir_id, .inst_id = import_inst_id}); + auto ref_id = context.AddInst(SemIR::ImportRefUsed{ + .type_id = namespace_type_id, .ir_id = ir_id, .inst_id = import_inst_id}); auto namespace_inst = SemIR::Namespace{namespace_type_id, SemIR::NameScopeId::Invalid, ref_id}; // Use the invalid node because there's no node to associate with. diff --git a/toolchain/check/testdata/namespace/add_to_import.carbon b/toolchain/check/testdata/namespace/add_to_import.carbon index b5aac87543fd..f600f14fc088 100644 --- a/toolchain/check/testdata/namespace/add_to_import.carbon +++ b/toolchain/check/testdata/namespace/add_to_import.carbon @@ -33,7 +33,7 @@ var a: i32 = NS.A(); // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {.NS = %.2, .a = %a} [template] -// CHECK:STDOUT: %import_ref = import_ref ir1, inst+1, unused +// CHECK:STDOUT: %import_ref: = import_ref ir1, inst+1, used // CHECK:STDOUT: %.2: = namespace {.A = %A}, %import_ref [template] // CHECK:STDOUT: %A: = fn_decl @A [template] // CHECK:STDOUT: %a.var: ref i32 = var a diff --git a/toolchain/check/testdata/namespace/fail_conflict_after_merge.carbon b/toolchain/check/testdata/namespace/fail_conflict_after_merge.carbon index f2d385f36d39..ece70aee5e18 100644 --- a/toolchain/check/testdata/namespace/fail_conflict_after_merge.carbon +++ b/toolchain/check/testdata/namespace/fail_conflict_after_merge.carbon @@ -51,7 +51,7 @@ fn NS(); // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {.NS = %.loc8_13.1} [template] -// CHECK:STDOUT: %import_ref = import_ref ir1, inst+1, unused +// CHECK:STDOUT: %import_ref: = import_ref ir1, inst+1, used // CHECK:STDOUT: %.loc8_13.1: = namespace {}, %import_ref [template] // CHECK:STDOUT: %.loc8_13.2: = namespace {} [template] // CHECK:STDOUT: %.loc16: = fn_decl @.1 [template] diff --git a/toolchain/check/testdata/namespace/fail_conflict_imported_namespace_first.carbon b/toolchain/check/testdata/namespace/fail_conflict_imported_namespace_first.carbon index ea49e131f5e8..e9eece50164a 100644 --- a/toolchain/check/testdata/namespace/fail_conflict_imported_namespace_first.carbon +++ b/toolchain/check/testdata/namespace/fail_conflict_imported_namespace_first.carbon @@ -37,7 +37,7 @@ fn NS.Foo(); // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {.NS = %.2} [template] -// CHECK:STDOUT: %import_ref = import_ref ir1, inst+1, unused +// CHECK:STDOUT: %import_ref: = import_ref ir1, inst+1, used // CHECK:STDOUT: %.2: = namespace {.Foo = %Foo}, %import_ref [template] // CHECK:STDOUT: %.loc12: = fn_decl @.1 [template] // CHECK:STDOUT: %Foo: = fn_decl @Foo [template] 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 db1c7478bbdd..b889adcfcc37 100644 --- a/toolchain/check/testdata/namespace/fail_conflict_imported_namespace_second.carbon +++ b/toolchain/check/testdata/namespace/fail_conflict_imported_namespace_second.carbon @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE +// CHECK:STDERR: conflict.carbon: ERROR: Semantics TODO: `TODO: ResolveIfImportRefUnused for FunctionDecl`. // --- fn.carbon @@ -16,10 +17,12 @@ package Example api; import library "fn"; -// CHECK:STDERR: conflict.carbon:[[@LINE+4]]:1: ERROR: Duplicate name being declared in the same scope. +// CHECK:STDERR: conflict.carbon:[[@LINE+6]]:1: ERROR: Duplicate name being declared in the same scope. // CHECK:STDERR: namespace NS; // CHECK:STDERR: ^~~~~~~~~~~~~ -// CHECK:STDERR: conflict.carbon: Name is previously declared here. +// CHECK:STDERR: fn.carbon:4:1: Name is previously declared here. +// CHECK:STDERR: fn NS(); +// CHECK:STDERR: ^~~~~~~~ namespace NS; // CHECK:STDERR: conflict.carbon:[[@LINE+6]]:7: ERROR: Name qualifiers are only allowed for entities that provide a scope. @@ -42,13 +45,11 @@ fn NS.Foo(); // CHECK:STDOUT: --- conflict.carbon // CHECK:STDOUT: // CHECK:STDOUT: file { -// CHECK:STDOUT: package: = namespace {.NS = %.2} [template] -// CHECK:STDOUT: %.2: = fn_decl @.1 [template] -// CHECK:STDOUT: %.loc10: = namespace {} [template] -// CHECK:STDOUT: %.loc18: = fn_decl @.2 [template] +// CHECK:STDOUT: package: = namespace {.NS = %import_ref} [template] +// CHECK:STDOUT: %import_ref: = import_ref ir1, inst+1, used +// CHECK:STDOUT: %.loc12: = namespace {} [template] +// CHECK:STDOUT: %.loc20: = fn_decl @.1 [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @.1(); // CHECK:STDOUT: -// CHECK:STDOUT: fn @.2(); -// CHECK:STDOUT: diff --git a/toolchain/check/testdata/namespace/fail_conflict_in_imports_namespace_first.carbon b/toolchain/check/testdata/namespace/fail_conflict_in_imports_namespace_first.carbon index 13e0e3d1333c..705098a02c4c 100644 --- a/toolchain/check/testdata/namespace/fail_conflict_in_imports_namespace_first.carbon +++ b/toolchain/check/testdata/namespace/fail_conflict_in_imports_namespace_first.carbon @@ -61,7 +61,7 @@ fn NS.Bar() {} // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {.NS = %.2} [template] -// CHECK:STDOUT: %import_ref.1 = import_ref ir1, inst+1, unused +// CHECK:STDOUT: %import_ref.1: = import_ref ir1, inst+1, used // CHECK:STDOUT: %.2: = namespace {.Foo = %import_ref.2, .Bar = %Bar}, %import_ref.1 [template] // CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+2, unused // CHECK:STDOUT: %import_ref.3 = import_ref ir2, inst+1, unused diff --git a/toolchain/check/testdata/namespace/fail_conflict_in_imports_namespace_second.carbon b/toolchain/check/testdata/namespace/fail_conflict_in_imports_namespace_second.carbon index 4dc80b3b5a56..c068f40e382f 100644 --- a/toolchain/check/testdata/namespace/fail_conflict_in_imports_namespace_second.carbon +++ b/toolchain/check/testdata/namespace/fail_conflict_in_imports_namespace_second.carbon @@ -62,7 +62,7 @@ fn NS.Bar() {} // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {.NS = %.2} [template] // CHECK:STDOUT: %import_ref.1 = import_ref ir1, inst+1, unused -// CHECK:STDOUT: %import_ref.2 = import_ref ir2, inst+1, unused +// CHECK:STDOUT: %import_ref.2: = import_ref ir2, inst+1, used // CHECK:STDOUT: %.2: = namespace {.Foo = %import_ref.3, .Bar = %Bar}, %import_ref.2 [template] // CHECK:STDOUT: %import_ref.3 = import_ref ir2, inst+2, unused // CHECK:STDOUT: %Bar: = fn_decl @Bar [template] diff --git a/toolchain/check/testdata/namespace/imported.carbon b/toolchain/check/testdata/namespace/fail_todo_imported.carbon similarity index 73% rename from toolchain/check/testdata/namespace/imported.carbon rename to toolchain/check/testdata/namespace/fail_todo_imported.carbon index 2dcee03e4710..4bbb9246e60e 100644 --- a/toolchain/check/testdata/namespace/imported.carbon +++ b/toolchain/check/testdata/namespace/fail_todo_imported.carbon @@ -3,6 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE +// CHECK:STDERR: implicit.impl.carbon: ERROR: Semantics TODO: `TODO: ResolveIfImportRefUnused for FunctionDecl`. +// CHECK:STDERR: implicit.impl.carbon: ERROR: Semantics TODO: `TODO: ResolveIfImportRefUnused for FunctionDecl`. // --- implicit.carbon @@ -46,38 +48,35 @@ var package_b: () = package.NS.ChildNS.B(); // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {.NS = %.2, .a = %a, .b = %b, .package_a = %package_a, .package_b = %package_b} [template] -// CHECK:STDOUT: %import_ref.1 = import_ref ir1, inst+1, unused -// CHECK:STDOUT: %.2: = namespace {.ChildNS = %.3, .A = %.4}, %import_ref.1 [template] -// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+2, unused -// CHECK:STDOUT: %.3: = namespace {.B = %.5}, %import_ref.2 [template] -// CHECK:STDOUT: %.4: = fn_decl @.1 [template] -// CHECK:STDOUT: %.5: = fn_decl @.2 [template] +// CHECK:STDOUT: %import_ref.1: = import_ref ir1, inst+1, used +// CHECK:STDOUT: %.2: = namespace {.ChildNS = %.3, .A = %import_ref.3}, %import_ref.1 [template] +// CHECK:STDOUT: %import_ref.2: = import_ref ir1, inst+2, used +// CHECK:STDOUT: %.3: = namespace {.B = %import_ref.4}, %import_ref.2 [template] +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+3, used +// CHECK:STDOUT: %import_ref.4: = import_ref ir1, inst+4, used // CHECK:STDOUT: %.loc4_9.1: () = tuple_literal () // CHECK:STDOUT: %.loc4_9.2: type = converted %.loc4_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: %NS.ref.loc4: = name_ref NS, %.2 [template = %.2] -// CHECK:STDOUT: %A.ref.loc4: = name_ref A, %.4 [template = %.4] -// CHECK:STDOUT: %.loc4_17: init () = call %A.ref.loc4() -// CHECK:STDOUT: assign %a.var, %.loc4_17 +// CHECK:STDOUT: %A.ref.loc4: = name_ref A, %import_ref.3 +// CHECK:STDOUT: assign %a.var, // CHECK:STDOUT: %.loc5_9.1: () = tuple_literal () // CHECK:STDOUT: %.loc5_9.2: type = converted %.loc5_9.1, constants.%.1 [template = constants.%.1] // CHECK:STDOUT: %b.var: ref () = var b // CHECK:STDOUT: %b: ref () = bind_name b, %b.var // CHECK:STDOUT: %NS.ref.loc5: = name_ref NS, %.2 [template = %.2] // CHECK:STDOUT: %ChildNS.ref.loc5: = name_ref ChildNS, %.3 [template = %.3] -// CHECK:STDOUT: %B.ref.loc5: = name_ref B, %.5 [template = %.5] -// CHECK:STDOUT: %.loc5_25: init () = call %B.ref.loc5() -// CHECK:STDOUT: assign %b.var, %.loc5_25 +// CHECK:STDOUT: %B.ref.loc5: = name_ref B, %import_ref.4 +// CHECK:STDOUT: assign %b.var, // CHECK:STDOUT: %.loc7_17.1: () = tuple_literal () // CHECK:STDOUT: %.loc7_17.2: type = converted %.loc7_17.1, constants.%.1 [template = constants.%.1] // CHECK:STDOUT: %package_a.var: ref () = var package_a // CHECK:STDOUT: %package_a: ref () = bind_name package_a, %package_a.var // CHECK:STDOUT: %package.ref.loc7: = name_ref package, package [template = package] // CHECK:STDOUT: %NS.ref.loc7: = name_ref NS, %.2 [template = %.2] -// CHECK:STDOUT: %A.ref.loc7: = name_ref A, %.4 [template = %.4] -// CHECK:STDOUT: %.loc7_33: init () = call %A.ref.loc7() -// CHECK:STDOUT: assign %package_a.var, %.loc7_33 +// CHECK:STDOUT: %A.ref.loc7: = name_ref A, %import_ref.3 +// CHECK:STDOUT: assign %package_a.var, // CHECK:STDOUT: %.loc8_17.1: () = tuple_literal () // CHECK:STDOUT: %.loc8_17.2: type = converted %.loc8_17.1, constants.%.1 [template = constants.%.1] // CHECK:STDOUT: %package_b.var: ref () = var package_b @@ -85,12 +84,7 @@ var package_b: () = package.NS.ChildNS.B(); // CHECK:STDOUT: %package.ref.loc8: = name_ref package, package [template = package] // CHECK:STDOUT: %NS.ref.loc8: = name_ref NS, %.2 [template = %.2] // CHECK:STDOUT: %ChildNS.ref.loc8: = name_ref ChildNS, %.3 [template = %.3] -// CHECK:STDOUT: %B.ref.loc8: = name_ref B, %.5 [template = %.5] -// CHECK:STDOUT: %.loc8_41: init () = call %B.ref.loc8() -// CHECK:STDOUT: assign %package_b.var, %.loc8_41 +// CHECK:STDOUT: %B.ref.loc8: = name_ref B, %import_ref.4 +// CHECK:STDOUT: assign %package_b.var, // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @.1(); -// CHECK:STDOUT: -// CHECK:STDOUT: fn @.2(); -// CHECK:STDOUT: diff --git a/toolchain/check/testdata/namespace/imported_indirect.carbon b/toolchain/check/testdata/namespace/fail_todo_imported_indirect.carbon similarity index 74% rename from toolchain/check/testdata/namespace/imported_indirect.carbon rename to toolchain/check/testdata/namespace/fail_todo_imported_indirect.carbon index dc9f7e3b85d8..a19132765ec6 100644 --- a/toolchain/check/testdata/namespace/imported_indirect.carbon +++ b/toolchain/check/testdata/namespace/fail_todo_imported_indirect.carbon @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE +// CHECK:STDERR: e.carbon: ERROR: Semantics TODO: `TODO: ResolveIfImportRefUnused for FunctionDecl`. // --- a.carbon @@ -49,7 +50,7 @@ var e: () = A.B.C.D(); // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {.A = %.2} [template] -// CHECK:STDOUT: %import_ref = import_ref ir1, inst+1, unused +// CHECK:STDOUT: %import_ref: = import_ref ir1, inst+1, used // CHECK:STDOUT: %.2: = namespace {.B = %.loc5}, %import_ref [template] // CHECK:STDOUT: %.loc5: = namespace {} [template] // CHECK:STDOUT: } @@ -58,9 +59,9 @@ var e: () = A.B.C.D(); // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {.A = %.2} [template] -// CHECK:STDOUT: %import_ref.1 = import_ref ir1, inst+2, unused +// CHECK:STDOUT: %import_ref.1: = import_ref ir1, inst+2, used // CHECK:STDOUT: %.2: = namespace {.B = %.3}, %import_ref.1 [template] -// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+3, unused +// CHECK:STDOUT: %import_ref.2: = import_ref ir1, inst+3, used // CHECK:STDOUT: %.3: = namespace {.C = %.loc5}, %import_ref.2 [template] // CHECK:STDOUT: %.loc5: = namespace {} [template] // CHECK:STDOUT: } @@ -69,11 +70,11 @@ var e: () = A.B.C.D(); // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {.A = %.2} [template] -// CHECK:STDOUT: %import_ref.1 = import_ref ir1, inst+2, unused +// CHECK:STDOUT: %import_ref.1: = import_ref ir1, inst+2, used // CHECK:STDOUT: %.2: = namespace {.B = %.3}, %import_ref.1 [template] -// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+4, unused +// CHECK:STDOUT: %import_ref.2: = import_ref ir1, inst+4, used // CHECK:STDOUT: %.3: = namespace {.C = %.4}, %import_ref.2 [template] -// CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+5, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+5, used // CHECK:STDOUT: %.4: = namespace {.D = %D}, %import_ref.3 [template] // CHECK:STDOUT: %D: = fn_decl @D [template] // CHECK:STDOUT: } @@ -91,13 +92,13 @@ var e: () = A.B.C.D(); // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {.A = %.2, .e = %e} [template] -// CHECK:STDOUT: %import_ref.1 = import_ref ir1, inst+2, unused +// CHECK:STDOUT: %import_ref.1: = import_ref ir1, inst+2, used // CHECK:STDOUT: %.2: = namespace {.B = %.3}, %import_ref.1 [template] -// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+4, unused +// CHECK:STDOUT: %import_ref.2: = import_ref ir1, inst+4, used // CHECK:STDOUT: %.3: = namespace {.C = %.4}, %import_ref.2 [template] -// CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+6, unused -// CHECK:STDOUT: %.4: = namespace {.D = %.5}, %import_ref.3 [template] -// CHECK:STDOUT: %.5: = fn_decl @.1 [template] +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+6, used +// CHECK:STDOUT: %.4: = namespace {.D = %import_ref.4}, %import_ref.3 [template] +// CHECK:STDOUT: %import_ref.4: = import_ref ir1, inst+7, used // CHECK:STDOUT: %.loc5_9.1: () = tuple_literal () // CHECK:STDOUT: %.loc5_9.2: type = converted %.loc5_9.1, constants.%.1 [template = constants.%.1] // CHECK:STDOUT: %e.var: ref () = var e @@ -105,10 +106,7 @@ var e: () = A.B.C.D(); // CHECK:STDOUT: %A.ref: = name_ref A, %.2 [template = %.2] // CHECK:STDOUT: %B.ref: = name_ref B, %.3 [template = %.3] // CHECK:STDOUT: %C.ref: = name_ref C, %.4 [template = %.4] -// CHECK:STDOUT: %D.ref: = name_ref D, %.5 [template = %.5] -// CHECK:STDOUT: %.loc5_20: init () = call %D.ref() -// CHECK:STDOUT: assign %e.var, %.loc5_20 +// CHECK:STDOUT: %D.ref: = name_ref D, %import_ref.4 +// CHECK:STDOUT: assign %e.var, // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @.1(); -// CHECK:STDOUT: diff --git a/toolchain/check/testdata/namespace/merging.carbon b/toolchain/check/testdata/namespace/fail_todo_merging.carbon similarity index 75% rename from toolchain/check/testdata/namespace/merging.carbon rename to toolchain/check/testdata/namespace/fail_todo_merging.carbon index 97178c48ff48..ac3b271a3fdb 100644 --- a/toolchain/check/testdata/namespace/merging.carbon +++ b/toolchain/check/testdata/namespace/fail_todo_merging.carbon @@ -3,6 +3,9 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE +// CHECK:STDERR: c.carbon: ERROR: Semantics TODO: `TODO: ResolveIfImportRefUnused for FunctionDecl`. +// CHECK:STDERR: c.carbon: ERROR: Semantics TODO: `TODO: ResolveIfImportRefUnused for FunctionDecl`. +// CHECK:STDERR: c.carbon: ERROR: Semantics TODO: `TODO: ResolveIfImportRefUnused for FunctionDecl`. // --- a.carbon @@ -83,11 +86,11 @@ fn Run() { // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {.NS = %.loc7_13.1, .Run = %Run} [template] -// CHECK:STDOUT: %import_ref = import_ref ir1, inst+1, unused -// CHECK:STDOUT: %.loc7_13.1: = namespace {.A = %.2, .B1 = %.3, .B2 = %.4, .C = %C}, %import_ref [template] -// CHECK:STDOUT: %.2: = fn_decl @.1 [template] -// CHECK:STDOUT: %.3: = fn_decl @.2 [template] -// CHECK:STDOUT: %.4: = fn_decl @.3 [template] +// CHECK:STDOUT: %import_ref.1: = import_ref ir1, inst+1, used +// CHECK:STDOUT: %.loc7_13.1: = namespace {.A = %import_ref.2, .B1 = %import_ref.3, .B2 = %import_ref.4, .C = %C}, %import_ref.1 [template] +// CHECK:STDOUT: %import_ref.2: = import_ref ir1, inst+2, used +// CHECK:STDOUT: %import_ref.3: = import_ref ir2, inst+2, used +// CHECK:STDOUT: %import_ref.4: = import_ref ir2, inst+5, used // CHECK:STDOUT: %.loc7_13.2: = namespace {} [template] // CHECK:STDOUT: %C: = fn_decl @C [template] // CHECK:STDOUT: %Run: = fn_decl @Run [template] @@ -101,23 +104,14 @@ fn Run() { // CHECK:STDOUT: fn @Run() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %NS.ref.loc12: = name_ref NS, file.%.loc7_13.1 [template = file.%.loc7_13.1] -// CHECK:STDOUT: %A.ref: = name_ref A, file.%.2 [template = file.%.2] -// CHECK:STDOUT: %.loc12: init () = call %A.ref() +// CHECK:STDOUT: %A.ref: = name_ref A, file.%import_ref.2 // CHECK:STDOUT: %NS.ref.loc13: = name_ref NS, file.%.loc7_13.1 [template = file.%.loc7_13.1] -// CHECK:STDOUT: %B1.ref: = name_ref B1, file.%.3 [template = file.%.3] -// CHECK:STDOUT: %.loc13: init () = call %B1.ref() +// CHECK:STDOUT: %B1.ref: = name_ref B1, file.%import_ref.3 // CHECK:STDOUT: %NS.ref.loc14: = name_ref NS, file.%.loc7_13.1 [template = file.%.loc7_13.1] -// CHECK:STDOUT: %B2.ref: = name_ref B2, file.%.4 [template = file.%.4] -// CHECK:STDOUT: %.loc14: init () = call %B2.ref() +// CHECK:STDOUT: %B2.ref: = name_ref B2, file.%import_ref.4 // CHECK:STDOUT: %NS.ref.loc15: = name_ref NS, file.%.loc7_13.1 [template = file.%.loc7_13.1] // CHECK:STDOUT: %C.ref: = name_ref C, file.%C [template = file.%C] // CHECK:STDOUT: %.loc15: init () = call %C.ref() // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @.1(); -// CHECK:STDOUT: -// CHECK:STDOUT: fn @.2(); -// CHECK:STDOUT: -// CHECK:STDOUT: fn @.3(); -// CHECK:STDOUT: diff --git a/toolchain/check/testdata/packages/loaded_global.carbon b/toolchain/check/testdata/packages/fail_todo_loaded_global.carbon similarity index 71% rename from toolchain/check/testdata/packages/loaded_global.carbon rename to toolchain/check/testdata/packages/fail_todo_loaded_global.carbon index 278bda7407d2..bf638c0ea3a3 100644 --- a/toolchain/check/testdata/packages/loaded_global.carbon +++ b/toolchain/check/testdata/packages/fail_todo_loaded_global.carbon @@ -3,6 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE +// CHECK:STDERR: implicit.impl.carbon: ERROR: Semantics TODO: `TODO: ResolveIfImportRefUnused for FunctionDecl`. +// CHECK:STDERR: same_package_importer.carbon: ERROR: Semantics TODO: `TODO: ResolveIfImportRefUnused for FunctionDecl`. // --- implicit.carbon @@ -50,27 +52,23 @@ var package_b: () = package.B(); // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { -// CHECK:STDOUT: package: = namespace {.A = %.2, .a = %a, .package_a = %package_a} [template] -// CHECK:STDOUT: %.2: = fn_decl @.1 [template] +// CHECK:STDOUT: package: = namespace {.A = %import_ref, .a = %a, .package_a = %package_a} [template] +// CHECK:STDOUT: %import_ref: = import_ref ir1, inst+1, used // CHECK:STDOUT: %.loc4_9.1: () = tuple_literal () // CHECK:STDOUT: %.loc4_9.2: type = converted %.loc4_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.ref.loc4: = name_ref A, %.2 [template = %.2] -// CHECK:STDOUT: %.loc4_14: init () = call %A.ref.loc4() -// CHECK:STDOUT: assign %a.var, %.loc4_14 +// CHECK:STDOUT: %A.ref.loc4: = name_ref A, %import_ref +// CHECK:STDOUT: assign %a.var, // CHECK:STDOUT: %.loc6_17.1: () = tuple_literal () // CHECK:STDOUT: %.loc6_17.2: type = converted %.loc6_17.1, constants.%.1 [template = constants.%.1] // CHECK:STDOUT: %package_a.var: ref () = var package_a // CHECK:STDOUT: %package_a: ref () = bind_name package_a, %package_a.var // CHECK:STDOUT: %package.ref: = name_ref package, package [template = package] -// CHECK:STDOUT: %A.ref.loc6: = name_ref A, %.2 [template = %.2] -// CHECK:STDOUT: %.loc6_30: init () = call %A.ref.loc6() -// CHECK:STDOUT: assign %package_a.var, %.loc6_30 +// CHECK:STDOUT: %A.ref.loc6: = name_ref A, %import_ref +// CHECK:STDOUT: assign %package_a.var, // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @.1(); -// CHECK:STDOUT: // CHECK:STDOUT: --- same_package.carbon // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -87,24 +85,20 @@ var package_b: () = package.B(); // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { -// CHECK:STDOUT: package: = namespace {.B = %.2, .b = %b, .package_b = %package_b} [template] -// CHECK:STDOUT: %.2: = fn_decl @.1 [template] +// CHECK:STDOUT: package: = namespace {.B = %import_ref, .b = %b, .package_b = %package_b} [template] +// CHECK:STDOUT: %import_ref: = import_ref ir1, inst+1, used // CHECK:STDOUT: %.loc6_9.1: () = tuple_literal () // CHECK:STDOUT: %.loc6_9.2: type = converted %.loc6_9.1, constants.%.1 [template = constants.%.1] // CHECK:STDOUT: %b.var: ref () = var b // CHECK:STDOUT: %b: ref () = bind_name b, %b.var -// CHECK:STDOUT: %B.ref.loc6: = name_ref B, %.2 [template = %.2] -// CHECK:STDOUT: %.loc6_14: init () = call %B.ref.loc6() -// CHECK:STDOUT: assign %b.var, %.loc6_14 +// CHECK:STDOUT: %B.ref.loc6: = name_ref B, %import_ref +// CHECK:STDOUT: assign %b.var, // CHECK:STDOUT: %.loc8_17.1: () = tuple_literal () // CHECK:STDOUT: %.loc8_17.2: type = converted %.loc8_17.1, constants.%.1 [template = constants.%.1] // CHECK:STDOUT: %package_b.var: ref () = var package_b // CHECK:STDOUT: %package_b: ref () = bind_name package_b, %package_b.var // CHECK:STDOUT: %package.ref: = name_ref package, package [template = package] -// CHECK:STDOUT: %B.ref.loc8: = name_ref B, %.2 [template = %.2] -// CHECK:STDOUT: %.loc8_30: init () = call %B.ref.loc8() -// CHECK:STDOUT: assign %package_b.var, %.loc8_30 +// CHECK:STDOUT: %B.ref.loc8: = name_ref B, %import_ref +// CHECK:STDOUT: assign %package_b.var, // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @.1(); -// CHECK:STDOUT: diff --git a/toolchain/check/testdata/packages/fail_todo_lazy_import_ref.carbon b/toolchain/check/testdata/var/fail_todo_import.carbon similarity index 85% rename from toolchain/check/testdata/packages/fail_todo_lazy_import_ref.carbon rename to toolchain/check/testdata/var/fail_todo_import.carbon index 8ff24993d9ce..8a633b9f89e5 100644 --- a/toolchain/check/testdata/packages/fail_todo_lazy_import_ref.carbon +++ b/toolchain/check/testdata/var/fail_todo_import.carbon @@ -6,7 +6,7 @@ // then, update it whenever its target is implemented. // // AUTOUPDATE -// CHECK:STDERR: implicit.impl.carbon: ERROR: Semantics TODO: `TODO: support BindName`. +// CHECK:STDERR: implicit.impl.carbon: ERROR: Semantics TODO: `TODO: ResolveIfImportRefUnused for BindName`. // --- implicit.carbon @@ -41,13 +41,13 @@ var a: () = a_ref; // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { -// CHECK:STDOUT: package: = namespace {.a_ref = %package.var, .a = %a} [template] -// CHECK:STDOUT: %package.var: ref = var package +// CHECK:STDOUT: package: = namespace {.a_ref = %import_ref, .a = %a} [template] +// CHECK:STDOUT: %import_ref: = import_ref ir1, inst+2, used // CHECK:STDOUT: %.loc4_9.1: () = tuple_literal () // CHECK:STDOUT: %.loc4_9.2: type = converted %.loc4_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_ref.ref: ref = name_ref a_ref, %package.var +// CHECK:STDOUT: %a_ref.ref: = name_ref a_ref, %import_ref // CHECK:STDOUT: assign %a.var, // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/lower/handle.cpp b/toolchain/lower/handle.cpp index fadf9e526a84..5b24b0530853 100644 --- a/toolchain/lower/handle.cpp +++ b/toolchain/lower/handle.cpp @@ -206,6 +206,12 @@ auto HandleImportRefUnused(FunctionContext& /*context*/, FatalErrorIfEncountered(inst); } +auto HandleImportRefUsed(FunctionContext& /*context*/, + SemIR::InstId /*inst_id*/, SemIR::ImportRefUsed inst) + -> void { + FatalErrorIfEncountered(inst); +} + auto HandleInitializeFrom(FunctionContext& context, SemIR::InstId /*inst_id*/, SemIR::InitializeFrom inst) -> void { auto storage_type_id = context.sem_ir().insts().Get(inst.dest_id).type_id(); diff --git a/toolchain/sem_ir/file.cpp b/toolchain/sem_ir/file.cpp index b293962b9df9..3375c5041339 100644 --- a/toolchain/sem_ir/file.cpp +++ b/toolchain/sem_ir/file.cpp @@ -206,6 +206,7 @@ static auto GetTypePrecedence(InstKind kind) -> int { case BindSymbolicName::Kind: case Builtin::Kind: case ClassType::Kind: + case ImportRefUsed::Kind: case NameRef::Kind: case StructType::Kind: case TupleType::Kind: @@ -355,6 +356,9 @@ auto File::StringifyTypeExpr(InstId outer_inst_id) const -> std::string { } break; } + case ImportRefUsed::Kind: + out << ""; + break; case NameRef::Kind: { out << names().GetFormatted(inst.As().name_id); break; @@ -510,6 +514,7 @@ auto GetExprCategory(const File& file, InstId inst_id) -> ExprCategory { case FunctionDecl::Kind: case Import::Kind: case ImportRefUnused::Kind: + case ImportRefUsed::Kind: case InterfaceDecl::Kind: case Namespace::Kind: case Return::Kind: diff --git a/toolchain/sem_ir/formatter.cpp b/toolchain/sem_ir/formatter.cpp index 71692a5c87e5..4bc17f538392 100644 --- a/toolchain/sem_ir/formatter.cpp +++ b/toolchain/sem_ir/formatter.cpp @@ -493,7 +493,8 @@ class InstNamer { add_inst_name("import"); continue; } - case ImportRefUnused::Kind: { + case ImportRefUnused::Kind: + case ImportRefUsed::Kind: { add_inst_name("import_ref"); continue; } @@ -953,6 +954,12 @@ class Formatter { out_ << " " << inst.ir_id << ", " << inst.inst_id << ", unused"; } + auto FormatInstructionRHS(ImportRefUsed inst) -> void { + // Don't format the inst_id because it refers to a different IR. + // TODO: Consider a better way to format the InstID from other IRs. + out_ << " " << inst.ir_id << ", " << inst.inst_id << ", used"; + } + auto FormatInstructionRHS(SpliceBlock inst) -> void { FormatArgs(inst.result_id); out_ << " {"; diff --git a/toolchain/sem_ir/inst_kind.def b/toolchain/sem_ir/inst_kind.def index 675d1105e0d5..16ef241b9378 100644 --- a/toolchain/sem_ir/inst_kind.def +++ b/toolchain/sem_ir/inst_kind.def @@ -47,6 +47,7 @@ CARBON_SEM_IR_INST_KIND(FieldDecl) CARBON_SEM_IR_INST_KIND(FunctionDecl) CARBON_SEM_IR_INST_KIND(Import) CARBON_SEM_IR_INST_KIND(ImportRefUnused) +CARBON_SEM_IR_INST_KIND(ImportRefUsed) CARBON_SEM_IR_INST_KIND(InitializeFrom) CARBON_SEM_IR_INST_KIND(InterfaceDecl) CARBON_SEM_IR_INST_KIND(IntLiteral) diff --git a/toolchain/sem_ir/typed_insts.h b/toolchain/sem_ir/typed_insts.h index dd04faab72b8..4157088c5f0f 100644 --- a/toolchain/sem_ir/typed_insts.h +++ b/toolchain/sem_ir/typed_insts.h @@ -416,6 +416,16 @@ struct Import { CrossRefIRId last_cross_ref_ir_id; }; +// Common representation for all kinds of `ImportRef*` node. +struct AnyImportRef { + static constexpr InstKind Kinds[] = {InstKind::ImportRefUnused, + InstKind::ImportRefUsed}; + + InstKind kind; + CrossRefIRId ir_id; + InstId inst_id; +}; + // An imported entity that hasn't yet been referenced. If referenced, it should // turn into an ImportRefUsed. // TODO: Add ImportRefUsed. @@ -428,6 +438,17 @@ struct ImportRefUnused { InstId inst_id; }; +// An imported entity that has a reference, and thus should be emitted. +struct ImportRefUsed { + // No parse node: any parse node logic must use the referenced IR. + static constexpr auto Kind = + InstKind::ImportRefUsed.Define("import_ref"); + + TypeId type_id; + CrossRefIRId ir_id; + InstId inst_id; +}; + // Finalizes the initialization of `dest_id` from the initializer expression // `src_id`, by performing a final copy from source to destination, for types // whose initialization is not in-place.