From 239f8030a42ad3c43db57419b2bb01aea68ffd55 Mon Sep 17 00:00:00 2001 From: Jon Ross-Perkins Date: Tue, 28 Nov 2023 11:55:38 -0800 Subject: [PATCH] Pass imports to SemIR. (#3415) This adds instructions so that we get printing. I may adjust the instruction format a little further to add a type, but I think the basic setup will remain. Note this builds on #3414 --- toolchain/check/BUILD | 1 + toolchain/check/check.cpp | 131 +++++++++++++----- toolchain/check/context.cpp | 42 ++++++ toolchain/check/context.h | 7 + .../testdata/packages/explicit_imports.carbon | 4 + .../packages/fail_api_not_found.carbon | 5 + .../check/testdata/packages/fail_cycle.carbon | 10 ++ .../testdata/packages/fail_extension.carbon | 7 + .../packages/fail_import_default.carbon | 2 + .../packages/fail_import_invalid.carbon | 6 + .../packages/fail_import_repeat.carbon | 4 + .../testdata/packages/implicit_imports.carbon | 7 + toolchain/lower/handle.cpp | 8 ++ toolchain/sem_ir/BUILD | 2 + toolchain/sem_ir/builtin_kind.def | 2 +- toolchain/sem_ir/file.cpp | 4 + toolchain/sem_ir/file.h | 1 + toolchain/sem_ir/formatter.cpp | 9 +- toolchain/sem_ir/inst_kind.def | 1 + toolchain/sem_ir/typed_insts.h | 13 ++ 20 files changed, 228 insertions(+), 38 deletions(-) diff --git a/toolchain/check/BUILD b/toolchain/check/BUILD index 4519deae232a..ee7711d949ed 100644 --- a/toolchain/check/BUILD +++ b/toolchain/check/BUILD @@ -68,6 +68,7 @@ cc_library( "//toolchain/sem_ir:builtin_kind", "//toolchain/sem_ir:entry_point", "//toolchain/sem_ir:file", + "//toolchain/sem_ir:ids", "//toolchain/sem_ir:inst", "//toolchain/sem_ir:inst_kind", "@llvm-project//llvm:Support", diff --git a/toolchain/check/check.cpp b/toolchain/check/check.cpp index 67d0541a89da..a66a69666210 100644 --- a/toolchain/check/check.cpp +++ b/toolchain/check/check.cpp @@ -17,6 +17,27 @@ namespace Carbon::Check { struct UnitInfo { + // A given import within the file, with its destination. + struct Import { + Parse::Tree::PackagingNames names; + UnitInfo* unit_info; + }; + // A file's imports corresponding to a single package, for the map. + struct PackageImports { + // Use the constructor so that the SmallVector is only constructed + // as-needed. + explicit PackageImports(Parse::Node node) : node(node) {} + + // The first `import` directive in the file, which declared the package's + // identifier (even if the import failed). Used for associating diagnostics + // not specific to a single import. + Parse::Node node; + // Whether there's an import that failed to load. + bool has_load_error = false; + // The list of valid imports. + llvm::SmallVector imports; + }; + explicit UnitInfo(Unit& unit) : unit(&unit), translator(unit.tokens, unit.tokens->source().filename(), @@ -31,8 +52,11 @@ struct UnitInfo { ErrorTrackingDiagnosticConsumer err_tracker; DiagnosticEmitter emitter; - // A list of outgoing imports. - llvm::SmallVector> imports; + // A map of package names to outgoing imports. If the + // import's target isn't available, the unit will be nullptr to assist with + // name lookup. Invalid imports (for example, `import Main;`) aren't added + // because they won't add identifiers to name lookup. + llvm::DenseMap package_imports_map; // The remaining number of imports which must be checked before this unit can // be processed. @@ -43,6 +67,42 @@ struct UnitInfo { llvm::SmallVector incoming_imports; }; +// Add imports to the root block. +static auto AddImports(Context& context, UnitInfo& unit_info) -> void { + for (auto& [package_id, package_imports] : unit_info.package_imports_map) { + llvm::SmallVector sem_irs; + for (auto import : package_imports.imports) { + sem_irs.push_back(&**import.unit_info->unit->sem_ir); + } + context.AddPackageImports(package_imports.node, package_id, sem_irs, + package_imports.has_load_error); + } +} + +// Loops over all nodes in the tree. On some errors, this may return early, +// for example if an unrecoverable state is encountered. +static auto ProcessParseNodes(Context& context, + ErrorTrackingDiagnosticConsumer& err_tracker) + -> bool { + for (auto parse_node : context.parse_tree().postorder()) { + // clang warns on unhandled enum values; clang-tidy is incorrect here. + // NOLINTNEXTLINE(bugprone-switch-missing-default-case) + switch (auto parse_kind = context.parse_tree().node_kind(parse_node)) { +#define CARBON_PARSE_NODE_KIND(Name) \ + case Parse::NodeKind::Name: { \ + if (!Check::Handle##Name(context, parse_node)) { \ + CARBON_CHECK(err_tracker.seen_error()) \ + << "Handle" #Name " returned false without printing a diagnostic"; \ + return false; \ + } \ + break; \ + } +#include "toolchain/parse/node_kind.def" + } + } + return true; +} + // Produces and checks the IR for the provided Parse::Tree. // TODO: Both valid and invalid imports should be recorded on the SemIR. Invalid // imports should suppress errors where it makes sense. @@ -54,10 +114,9 @@ static auto CheckParseTree(const SemIR::File& builtin_ir, UnitInfo& unit_info, // For ease-of-access. SemIR::File& sem_ir = **unit_info.unit->sem_ir; - const Parse::Tree& parse_tree = *unit_info.unit->parse_tree; - Check::Context context(*unit_info.unit->tokens, unit_info.emitter, parse_tree, - sem_ir, vlog_stream); + Context context(*unit_info.unit->tokens, unit_info.emitter, + *unit_info.unit->parse_tree, sem_ir, vlog_stream); PrettyStackTraceFunction context_dumper( [&](llvm::raw_ostream& output) { context.PrintForStackDump(output); }); @@ -65,24 +124,11 @@ static auto CheckParseTree(const SemIR::File& builtin_ir, UnitInfo& unit_info, context.inst_block_stack().Push(); context.PushScope(); - // Loops over all nodes in the tree. On some errors, this may return early, - // for example if an unrecoverable state is encountered. - for (auto parse_node : parse_tree.postorder()) { - // clang warns on unhandled enum values; clang-tidy is incorrect here. - // NOLINTNEXTLINE(bugprone-switch-missing-default-case) - switch (auto parse_kind = parse_tree.node_kind(parse_node)) { -#define CARBON_PARSE_NODE_KIND(Name) \ - case Parse::NodeKind::Name: { \ - if (!Check::Handle##Name(context, parse_node)) { \ - CARBON_CHECK(unit_info.err_tracker.seen_error()) \ - << "Handle" #Name " returned false without printing a diagnostic"; \ - sem_ir.set_has_errors(true); \ - return; \ - } \ - break; \ - } -#include "toolchain/parse/node_kind.def" - } + AddImports(context, unit_info); + + if (!ProcessParseNodes(context, unit_info.err_tracker)) { + context.sem_ir().set_has_errors(true); + return; } // Pop information for the file-level scope. @@ -228,11 +274,19 @@ static auto TrackImport( return; } + // Get the package imports. + auto package_imports_it = + unit_info.package_imports_map.try_emplace(import.package_id, import.node) + .first; + if (auto api = api_map.find(import_key); api != api_map.end()) { - unit_info.imports.push_back({import.node, api->second}); + // Add references between the file and imported api. + package_imports_it->second.imports.push_back({import, api->second}); ++unit_info.imports_remaining; api->second->incoming_imports.push_back(&unit_info); } else { + // The imported api is missing. + package_imports_it->second.has_load_error = true; CARBON_DIAGNOSTIC(LibraryApiNotFound, Error, "Corresponding API not found."); CARBON_DIAGNOSTIC(ImportNotFound, Error, "Imported API not found."); @@ -392,17 +446,24 @@ auto CheckParseTrees(const SemIR::File& builtin_ir, // TODO: Better identify cycles, maybe try to untangle them. for (auto& unit_info : unit_infos) { if (unit_info.imports_remaining > 0) { - for (auto* import_it = unit_info.imports.begin(); - import_it != unit_info.imports.end();) { - auto* import_unit = import_it->second->unit; - if (*import_unit->sem_ir) { - ++import_it; - } else { - CARBON_DIAGNOSTIC(ImportCycleDetected, Error, - "Import cannot be used due to a cycle. Cycle " - "must be fixed to import."); - unit_info.emitter.Emit(import_it->first, ImportCycleDetected); - import_it = unit_info.imports.erase(import_it); + for (auto& [package_id, package_imports] : + unit_info.package_imports_map) { + for (auto* import_it = package_imports.imports.begin(); + import_it != package_imports.imports.end();) { + if (*import_it->unit_info->unit->sem_ir) { + // The import is checked, so continue. + ++import_it; + } else { + // The import hasn't been checked, indicating a cycle. + CARBON_DIAGNOSTIC(ImportCycleDetected, Error, + "Import cannot be used due to a cycle. Cycle " + "must be fixed to import."); + unit_info.emitter.Emit(import_it->names.node, + ImportCycleDetected); + // Make this look the same as an import which wasn't found. + package_imports.has_load_error = true; + import_it = package_imports.imports.erase(import_it); + } } } } diff --git a/toolchain/check/context.cpp b/toolchain/check/context.cpp index 9e1145662862..b49a31737188 100644 --- a/toolchain/check/context.cpp +++ b/toolchain/check/context.cpp @@ -15,8 +15,10 @@ #include "toolchain/lex/tokenized_buffer.h" #include "toolchain/parse/node_kind.h" #include "toolchain/sem_ir/file.h" +#include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/inst.h" #include "toolchain/sem_ir/inst_kind.h" +#include "toolchain/sem_ir/typed_insts.h" namespace Carbon::Check { @@ -112,6 +114,45 @@ auto Context::NoteIncompleteClass(SemIR::ClassId class_id, } } +auto Context::AddPackageImports(Parse::Node import_node, + IdentifierId package_id, + llvm::ArrayRef sem_irs, + bool has_load_error) -> void { + CARBON_CHECK(has_load_error || !sem_irs.empty()) + << "There should be either a load error or at least one IR."; + + auto name_id = SemIR::NameId::ForIdentifier(package_id); + + SemIR::CrossRefIRId first_id(cross_ref_irs().size()); + for (const auto* sem_ir : sem_irs) { + cross_ref_irs().Add(sem_ir); + } + if (has_load_error) { + cross_ref_irs().Add(nullptr); + } + SemIR::CrossRefIRId last_id(cross_ref_irs().size() - 1); + + auto type_id = GetBuiltinType(SemIR::BuiltinKind::NamespaceType); + auto inst_id = AddInst(SemIR::Import{.parse_node = import_node, + .type_id = type_id, + .first_cross_ref_ir_id = first_id, + .last_cross_ref_ir_id = last_id}); + if (name_id.is_valid()) { + // Add the import to lookup. Should always succeed because imports will be + // uniquely named. + AddNameToLookup(import_node, name_id, inst_id); + // Add a name for formatted output. This isn't used in name lookup in order + // to reduce indirection, but it's separate from the Import because it + // otherwise fits in an Inst. + AddInst(SemIR::BindName{.parse_node = import_node, + .type_id = type_id, + .name_id = name_id, + .value_id = inst_id}); + } else { + // TODO: All names from the current package should be added. + } +} + auto Context::AddNameToLookup(Parse::Node name_node, SemIR::NameId name_id, SemIR::InstId target_id) -> void { if (current_scope().names.insert(name_id).second) { @@ -811,6 +852,7 @@ class TypeCompleter { case SemIR::Deref::Kind: case SemIR::Field::Kind: case SemIR::FunctionDecl::Kind: + case SemIR::Import::Kind: case SemIR::InitializeFrom::Kind: case SemIR::IntegerLiteral::Kind: case SemIR::NameRef::Kind: diff --git a/toolchain/check/context.h b/toolchain/check/context.h index a5fd74a2ea82..918cb09454ea 100644 --- a/toolchain/check/context.h +++ b/toolchain/check/context.h @@ -14,6 +14,7 @@ #include "toolchain/check/node_stack.h" #include "toolchain/parse/tree.h" #include "toolchain/sem_ir/file.h" +#include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/inst.h" namespace Carbon::Check { @@ -62,6 +63,12 @@ class Context { // result. auto AddInstAndPush(Parse::Node parse_node, SemIR::Inst inst) -> void; + // Adds a package's imports to name lookup, with all libraries together. + // sem_irs will all be non-null; has_load_error must be used for any errors. + auto AddPackageImports(Parse::Node import_node, IdentifierId package_id, + llvm::ArrayRef sem_irs, + bool has_load_error) -> void; + // Adds a name to name lookup. Prints a diagnostic for name conflicts. auto AddNameToLookup(Parse::Node name_node, SemIR::NameId name_id, SemIR::InstId target_id) -> void; diff --git a/toolchain/check/testdata/packages/explicit_imports.carbon b/toolchain/check/testdata/packages/explicit_imports.carbon index fcd5b188b6bb..2da039b4979e 100644 --- a/toolchain/check/testdata/packages/explicit_imports.carbon +++ b/toolchain/check/testdata/packages/explicit_imports.carbon @@ -39,10 +39,14 @@ import library "lib"; // CHECK:STDOUT: file "api_lib.carbon" { // CHECK:STDOUT: } // CHECK:STDOUT: file "same_package.carbon" { +// CHECK:STDOUT: %import: = import ir1, ir2 // CHECK:STDOUT: } // CHECK:STDOUT: file "different_package.carbon" { +// CHECK:STDOUT: %import: = import ir1, ir2 +// CHECK:STDOUT: %Api: = bind_name Api, %import // CHECK:STDOUT: } // CHECK:STDOUT: file "main_lib_api.carbon" { // CHECK:STDOUT: } // CHECK:STDOUT: file "main_import.carbon" { +// CHECK:STDOUT: %import: = import ir1, ir1 // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/packages/fail_api_not_found.carbon b/toolchain/check/testdata/packages/fail_api_not_found.carbon index 1c80f34b3177..0992756ac9a2 100644 --- a/toolchain/check/testdata/packages/fail_api_not_found.carbon +++ b/toolchain/check/testdata/packages/fail_api_not_found.carbon @@ -26,8 +26,13 @@ package Foo library "Bar" impl; library "Bar" impl; // CHECK:STDOUT: file "no_api.impl.carbon" { +// CHECK:STDOUT: %import: = import ir1, ir1 +// CHECK:STDOUT: %Foo: = bind_name Foo, %import // CHECK:STDOUT: } // CHECK:STDOUT: file "no_api_lib.impl.carbon" { +// CHECK:STDOUT: %import: = import ir1, ir1 +// CHECK:STDOUT: %Foo: = bind_name Foo, %import // CHECK:STDOUT: } // CHECK:STDOUT: file "no_api_main_lib.impl.carbon" { +// CHECK:STDOUT: %import: = import ir1, ir1 // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/packages/fail_cycle.carbon b/toolchain/check/testdata/packages/fail_cycle.carbon index a151e6d70666..4fb97d86b4bd 100644 --- a/toolchain/check/testdata/packages/fail_cycle.carbon +++ b/toolchain/check/testdata/packages/fail_cycle.carbon @@ -48,12 +48,22 @@ package CycleChild api; import B; // CHECK:STDOUT: file "a.carbon" { +// CHECK:STDOUT: %import: = import ir1, ir1 +// CHECK:STDOUT: %B: = bind_name B, %import // CHECK:STDOUT: } // CHECK:STDOUT: file "b.carbon" { +// CHECK:STDOUT: %import: = import ir1, ir1 +// CHECK:STDOUT: %C: = bind_name C, %import // CHECK:STDOUT: } // CHECK:STDOUT: file "c.carbon" { +// CHECK:STDOUT: %import: = import ir1, ir1 +// CHECK:STDOUT: %A: = bind_name A, %import // CHECK:STDOUT: } // CHECK:STDOUT: file "c.impl.carbon" { +// CHECK:STDOUT: %import: = import ir1, ir1 +// CHECK:STDOUT: %C: = bind_name C, %import // CHECK:STDOUT: } // CHECK:STDOUT: file "cycle_child.carbon" { +// CHECK:STDOUT: %import: = import ir1, ir1 +// CHECK:STDOUT: %B: = bind_name B, %import // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/packages/fail_extension.carbon b/toolchain/check/testdata/packages/fail_extension.carbon index 2cc20f75f727..eb4df2fbbbe9 100644 --- a/toolchain/check/testdata/packages/fail_extension.carbon +++ b/toolchain/check/testdata/packages/fail_extension.carbon @@ -77,16 +77,23 @@ package SwappedExt impl; // CHECK:STDOUT: file "main_lib.incorrect" { // CHECK:STDOUT: } // CHECK:STDOUT: file "main_lib_impl.incorrect" { +// CHECK:STDOUT: %import: = import ir1, ir1 // CHECK:STDOUT: } // CHECK:STDOUT: file "package.incorrect" { // CHECK:STDOUT: } // CHECK:STDOUT: file "package_impl.incorrect" { +// CHECK:STDOUT: %import: = import ir1, ir1 +// CHECK:STDOUT: %Package: = bind_name Package, %import // CHECK:STDOUT: } // CHECK:STDOUT: file "package_lib.incorrect" { // CHECK:STDOUT: } // CHECK:STDOUT: file "package_lib_impl.incorrect" { +// CHECK:STDOUT: %import: = import ir1, ir1 +// CHECK:STDOUT: %Package: = bind_name Package, %import // CHECK:STDOUT: } // CHECK:STDOUT: file "swapped_ext.impl.carbon" { // CHECK:STDOUT: } // CHECK:STDOUT: file "swapped_ext.carbon" { +// CHECK:STDOUT: %import: = import ir1, ir1 +// CHECK:STDOUT: %SwappedExt: = bind_name SwappedExt, %import // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/packages/fail_import_default.carbon b/toolchain/check/testdata/packages/fail_import_default.carbon index b207d034a436..47d3eecc776a 100644 --- a/toolchain/check/testdata/packages/fail_import_default.carbon +++ b/toolchain/check/testdata/packages/fail_import_default.carbon @@ -41,6 +41,8 @@ import library default; // CHECK:STDOUT: file "default_api.carbon" { // CHECK:STDOUT: } // CHECK:STDOUT: file "default.impl.carbon" { +// CHECK:STDOUT: %import: = import ir1, ir1 +// CHECK:STDOUT: %A: = bind_name A, %import // CHECK:STDOUT: } // CHECK:STDOUT: file "main_import_default.carbon" { // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/packages/fail_import_invalid.carbon b/toolchain/check/testdata/packages/fail_import_invalid.carbon index 8ca30280da50..47e90dcb3d71 100644 --- a/toolchain/check/testdata/packages/fail_import_invalid.carbon +++ b/toolchain/check/testdata/packages/fail_import_invalid.carbon @@ -93,10 +93,16 @@ import ImportNotFound; // CHECK:STDOUT: file "implicit_api.carbon" { // CHECK:STDOUT: } // CHECK:STDOUT: file "implicit.impl.carbon" { +// CHECK:STDOUT: %import: = import ir1, ir1 +// CHECK:STDOUT: %Implicit: = bind_name Implicit, %import // CHECK:STDOUT: } // CHECK:STDOUT: file "implicit_lib_api.carbon" { // CHECK:STDOUT: } // CHECK:STDOUT: file "implicit_lib.impl.carbon" { +// CHECK:STDOUT: %import: = import ir1, ir1 +// CHECK:STDOUT: %Implicit: = bind_name Implicit, %import // CHECK:STDOUT: } // CHECK:STDOUT: file "not_found.carbon" { +// CHECK:STDOUT: %import: = import ir1, ir1 +// CHECK:STDOUT: %ImportNotFound: = bind_name ImportNotFound, %import // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/packages/fail_import_repeat.carbon b/toolchain/check/testdata/packages/fail_import_repeat.carbon index 98b678a0961c..a218c5cfc26f 100644 --- a/toolchain/check/testdata/packages/fail_import_repeat.carbon +++ b/toolchain/check/testdata/packages/fail_import_repeat.carbon @@ -65,6 +65,10 @@ import library default; // CHECK:STDOUT: file "main_lib.carbon" { // CHECK:STDOUT: } // CHECK:STDOUT: file "import.carbon" { +// CHECK:STDOUT: %import.loc2: = import ir1, ir2 +// CHECK:STDOUT: %Api: = bind_name Api, %import.loc2 +// CHECK:STDOUT: %import.loc20: = import ir3, ir3 // CHECK:STDOUT: } // CHECK:STDOUT: file "default_import.carbon" { +// CHECK:STDOUT: %import: = import ir1, ir1 // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/packages/implicit_imports.carbon b/toolchain/check/testdata/packages/implicit_imports.carbon index f512f0761b3c..5c9d9a4da679 100644 --- a/toolchain/check/testdata/packages/implicit_imports.carbon +++ b/toolchain/check/testdata/packages/implicit_imports.carbon @@ -50,16 +50,23 @@ library "lib" impl; // CHECK:STDOUT: file "with_impl.carbon" { // CHECK:STDOUT: } // CHECK:STDOUT: file "with_impl.impl.carbon" { +// CHECK:STDOUT: %import: = import ir1, ir1 +// CHECK:STDOUT: %WithImpl: = bind_name WithImpl, %import // CHECK:STDOUT: } // CHECK:STDOUT: file "with_impl_extra.impl.carbon" { +// CHECK:STDOUT: %import: = import ir1, ir1 +// CHECK:STDOUT: %WithImpl: = bind_name WithImpl, %import // CHECK:STDOUT: } // CHECK:STDOUT: file "with_impl_lib.carbon" { // CHECK:STDOUT: } // CHECK:STDOUT: file "with_impl_lib.impl.carbon" { +// CHECK:STDOUT: %import: = import ir1, ir1 +// CHECK:STDOUT: %WithImpl: = bind_name WithImpl, %import // CHECK:STDOUT: } // CHECK:STDOUT: file "main.carbon" { // CHECK:STDOUT: } // CHECK:STDOUT: file "main_lib.carbon" { // CHECK:STDOUT: } // CHECK:STDOUT: file "main_lib.impl.carbon" { +// CHECK:STDOUT: %import: = import ir1, ir1 // CHECK:STDOUT: } diff --git a/toolchain/lower/handle.cpp b/toolchain/lower/handle.cpp index e9348f4c97f5..ad6165435cdb 100644 --- a/toolchain/lower/handle.cpp +++ b/toolchain/lower/handle.cpp @@ -186,6 +186,14 @@ auto HandleFunctionDecl(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/, << inst; } +auto HandleImport(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/, + SemIR::Import inst) -> void { + CARBON_FATAL() + << "Should not be encountered. If that changes, we may want to change " + "higher-level logic to skip them rather than calling this. " + << 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/BUILD b/toolchain/sem_ir/BUILD index e161a24298f1..bc8b9d353487 100644 --- a/toolchain/sem_ir/BUILD +++ b/toolchain/sem_ir/BUILD @@ -65,6 +65,7 @@ cc_library( hdrs = ["file.h"], deps = [ ":builtin_kind", + ":ids", ":inst", ":inst_kind", ":value_stores", @@ -81,6 +82,7 @@ cc_library( hdrs = ["formatter.h"], deps = [ ":file", + ":ids", ":inst_kind", "//toolchain/base:value_store", "//toolchain/lex:tokenized_buffer", diff --git a/toolchain/sem_ir/builtin_kind.def b/toolchain/sem_ir/builtin_kind.def index 7345c04e4f23..32a010ce1b90 100644 --- a/toolchain/sem_ir/builtin_kind.def +++ b/toolchain/sem_ir/builtin_kind.def @@ -70,7 +70,7 @@ CARBON_SEM_IR_BUILTIN_KIND(FunctionType, "") // The type of bound method values. CARBON_SEM_IR_BUILTIN_KIND(BoundMethodType, "") -// The type of namespace names. +// The type of namespace and imported package names. CARBON_SEM_IR_BUILTIN_KIND(NamespaceType, "") // Keep invalid last, so that we can use values as array indices without needing diff --git a/toolchain/sem_ir/file.cpp b/toolchain/sem_ir/file.cpp index 3db4edbcdd87..b8b09db4be12 100644 --- a/toolchain/sem_ir/file.cpp +++ b/toolchain/sem_ir/file.cpp @@ -10,6 +10,7 @@ #include "toolchain/base/value_store.h" #include "toolchain/base/yaml.h" #include "toolchain/sem_ir/builtin_kind.h" +#include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/inst.h" #include "toolchain/sem_ir/inst_kind.h" @@ -203,6 +204,7 @@ static auto GetTypePrecedence(InstKind kind) -> int { case Deref::Kind: case Field::Kind: case FunctionDecl::Kind: + case Import::Kind: case InitializeFrom::Kind: case IntegerLiteral::Kind: case Namespace::Kind: @@ -406,6 +408,7 @@ auto File::StringifyTypeExpr(InstId outer_inst_id, bool in_type_context) const case Deref::Kind: case Field::Kind: case FunctionDecl::Kind: + case Import::Kind: case InitializeFrom::Kind: case IntegerLiteral::Kind: case Namespace::Kind: @@ -473,6 +476,7 @@ auto GetExprCategory(const File& file, InstId inst_id) -> ExprCategory { case ClassDecl::Kind: case Field::Kind: case FunctionDecl::Kind: + case Import::Kind: case Namespace::Kind: case NoOp::Kind: case Return::Kind: diff --git a/toolchain/sem_ir/file.h b/toolchain/sem_ir/file.h index 7dcbe85e0112..a0fa05a5d54f 100644 --- a/toolchain/sem_ir/file.h +++ b/toolchain/sem_ir/file.h @@ -11,6 +11,7 @@ #include "llvm/Support/FormatVariadic.h" #include "toolchain/base/value_store.h" #include "toolchain/base/yaml.h" +#include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/inst.h" #include "toolchain/sem_ir/value_stores.h" diff --git a/toolchain/sem_ir/formatter.cpp b/toolchain/sem_ir/formatter.cpp index 6f63ce9c1fbb..9da5630bfc91 100644 --- a/toolchain/sem_ir/formatter.cpp +++ b/toolchain/sem_ir/formatter.cpp @@ -11,6 +11,7 @@ #include "toolchain/base/value_store.h" #include "toolchain/lex/tokenized_buffer.h" #include "toolchain/parse/tree.h" +#include "toolchain/sem_ir/ids.h" namespace Carbon::SemIR { @@ -440,6 +441,10 @@ class InstNamer { sem_ir_.classes().Get(inst.As().class_id).name_id); continue; } + case Import::Kind: { + add_inst_name("import"); + continue; + } case NameRef::Kind: { add_inst_name_id(inst.As().name_id, ".ref"); continue; @@ -494,8 +499,6 @@ class Formatter { FormatConstants(); out_ << "file \"" << sem_ir_.filename() << "\" {\n"; - // TODO: Include information from the `package` declaration, once we - // fully support it. // TODO: Handle the case where there are multiple top-level instruction // blocks. For example, there may be branching in the initializer of a // global or a type expression. @@ -853,6 +856,8 @@ class Formatter { auto FormatArg(ClassId id) -> void { FormatClassName(id); } + auto FormatArg(CrossRefIRId id) -> void { out_ << id; } + auto FormatArg(IntegerId id) -> void { sem_ir_.integers().Get(id).print(out_, /*isSigned=*/false); } diff --git a/toolchain/sem_ir/inst_kind.def b/toolchain/sem_ir/inst_kind.def index 73820e2a6d8e..db2685f573b3 100644 --- a/toolchain/sem_ir/inst_kind.def +++ b/toolchain/sem_ir/inst_kind.def @@ -43,6 +43,7 @@ CARBON_SEM_IR_INST_KIND(CrossRef) CARBON_SEM_IR_INST_KIND(Deref) CARBON_SEM_IR_INST_KIND(Field) CARBON_SEM_IR_INST_KIND(FunctionDecl) +CARBON_SEM_IR_INST_KIND(Import) CARBON_SEM_IR_INST_KIND(InitializeFrom) CARBON_SEM_IR_INST_KIND(IntegerLiteral) CARBON_SEM_IR_INST_KIND(NameRef) diff --git a/toolchain/sem_ir/typed_insts.h b/toolchain/sem_ir/typed_insts.h index c26bcc4a718c..95e97a12d104 100644 --- a/toolchain/sem_ir/typed_insts.h +++ b/toolchain/sem_ir/typed_insts.h @@ -290,6 +290,19 @@ struct FunctionDecl { FunctionId function_id; }; +// An import corresponds to some number of IRs. The range of imported IRs is +// inclusive of last_cross_ref_ir_id, and will always be non-empty. If +// there was an import error, first_cross_ref_ir_id will reference a +// nullptr IR; there should only ever be one nullptr in the range. +struct Import { + static constexpr auto Kind = InstKind::Import.Define("import"); + + Parse::Node parse_node; + TypeId type_id; + CrossRefIRId first_cross_ref_ir_id; + CrossRefIRId last_cross_ref_ir_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.