From c1a894fca7104678b3b69a2f904dcabd98a64d1e Mon Sep 17 00:00:00 2001 From: Jon Ross-Perkins Date: Fri, 26 Jan 2024 09:26:15 -0800 Subject: [PATCH] Start adding ImportRefUsed, removing older copy behavior. (#3657) Builds on #3656. Under the prior "lazy" model, we had been planning to copy instructions. Under the current "unused+used" model, we're restricting that to constants. I'm trimming back some of the ResolveIfImportRefUnused logic because it was more appropriate for the former model. Right now, I'm adding ImportRefUsed direct creation in import.cpp for namespaces. I think I'll need to do something similar in RseolveIfImportRefUnused... I'm still trying to think about how to manage type information there (which needs to come in as an import reference itself, and probably have some amount of deduplication before forming a TypeId). So ImportRefUnused lacks a type because I'm hesitant to aggressively load it, whereas ImportRefUsed should *always* have a type but it's just an error while I think things through. For reference, ImportRefUnused and ImportRefUsed are mainly split in order to track the boolean "used" without making fundamental modifications to Inst for bit packing (this effectively instead packs a bit into InstKind). AnyImportRef currently excludes the type because it's mainly for diagnostic printing at the moment. It could end up with a TypeId that would end up Invalid for ImportRefUnused, though it could also be that the TypeId is only accessed when using ImportRefUsed explicitly. --- toolchain/check/check.cpp | 2 +- toolchain/check/context.cpp | 41 +++++-------------- toolchain/check/eval.cpp | 1 + toolchain/check/import.cpp | 4 +- .../testdata/namespace/add_to_import.carbon | 2 +- .../fail_conflict_after_merge.carbon | 2 +- ...l_conflict_imported_namespace_first.carbon | 2 +- ..._conflict_imported_namespace_second.carbon | 17 ++++---- ...conflict_in_imports_namespace_first.carbon | 2 +- ...onflict_in_imports_namespace_second.carbon | 2 +- ...orted.carbon => fail_todo_imported.carbon} | 38 ++++++++--------- ...bon => fail_todo_imported_indirect.carbon} | 30 +++++++------- ...erging.carbon => fail_todo_merging.carbon} | 28 +++++-------- ....carbon => fail_todo_loaded_global.carbon} | 34 +++++++-------- .../fail_todo_import.carbon} | 8 ++-- toolchain/lower/handle.cpp | 6 +++ toolchain/sem_ir/file.cpp | 5 +++ toolchain/sem_ir/formatter.cpp | 9 +++- toolchain/sem_ir/inst_kind.def | 1 + toolchain/sem_ir/typed_insts.h | 21 ++++++++++ 20 files changed, 129 insertions(+), 126 deletions(-) rename toolchain/check/testdata/namespace/{imported.carbon => fail_todo_imported.carbon} (73%) rename toolchain/check/testdata/namespace/{imported_indirect.carbon => fail_todo_imported_indirect.carbon} (74%) rename toolchain/check/testdata/namespace/{merging.carbon => fail_todo_merging.carbon} (75%) rename toolchain/check/testdata/packages/{loaded_global.carbon => fail_todo_loaded_global.carbon} (71%) rename toolchain/check/testdata/{packages/fail_todo_lazy_import_ref.carbon => var/fail_todo_import.carbon} (85%) 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.