// Part of the Carbon Language project, under the Apache License v2.0 with LLVM // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #ifndef CARBON_TOOLCHAIN_CHECK_CHECK_UNIT_H_ #define CARBON_TOOLCHAIN_CHECK_CHECK_UNIT_H_ #include "common/map.h" #include "llvm/ADT/SmallVector.h" #include "toolchain/check/check.h" #include "toolchain/check/context.h" #include "toolchain/sem_ir/ids.h" namespace Carbon::Check { struct UnitAndImports; // A file's imports corresponding to a single package, for // `UnitAndImports::package_imports`. struct PackageImports { // A given import within the file, with its destination. struct Import { Parse::Tree::PackagingNames names; UnitAndImports* unit_info; }; // Use the constructor so that the SmallVector is only constructed // as-needed. explicit PackageImports(IdentifierId package_id, Parse::ImportDeclId node_id) : package_id(package_id), node_id(node_id) {} // The identifier of the imported package. IdentifierId package_id; // The first `import` declaration 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::ImportDeclId node_id; // The associated `import` instruction. Has a value after a file is checked. SemIR::InstId import_decl_id = SemIR::InstId::None; // Whether there's an import that failed to load. bool has_load_error = false; // The list of valid imports. llvm::SmallVector imports; }; // Converts a `NodeId` to a diagnostic location for `UnitAndImports`. class UnitAndImportsDiagnosticConverter : public DiagnosticConverter { public: explicit UnitAndImportsDiagnosticConverter( Parse::GetTreeAndSubtreesFn get_parse_tree_and_subtrees) : get_parse_tree_and_subtrees_(get_parse_tree_and_subtrees) {} auto ConvertLoc(Parse::NodeId node_id, ContextFnT /*context_fn*/) const -> ConvertedDiagnosticLoc override { return get_parse_tree_and_subtrees_().NodeToDiagnosticLoc( node_id, /*token_only=*/false); } private: Parse::GetTreeAndSubtreesFn get_parse_tree_and_subtrees_; }; // Contains information accumulated while checking a `Unit` (primarily import // information), in addition to the `Unit` itself. struct UnitAndImports { explicit UnitAndImports(SemIR::CheckIRId check_ir_id, Unit& unit) : check_ir_id(check_ir_id), unit(&unit), err_tracker(*unit.consumer), converter(unit.get_parse_tree_and_subtrees), emitter(converter, err_tracker) {} auto parse_tree() -> const Parse::Tree& { return unit->sem_ir->parse_tree(); } auto source() -> const SourceBuffer& { return parse_tree().tokens().source(); } SemIR::CheckIRId check_ir_id; Unit* unit; // Emitter information. ErrorTrackingDiagnosticConsumer err_tracker; UnitAndImportsDiagnosticConverter converter; DiagnosticEmitter emitter; // List of the outgoing imports. If a package includes unavailable library // imports, it has an entry with has_load_error set. Invalid imports (for // example, `import Main;`) aren't added because they won't add identifiers to // name lookup. llvm::SmallVector package_imports; // A map of the package names to the outgoing imports above. Map package_imports_map; // List of the `import Cpp` imports. llvm::SmallVector cpp_imports; // The remaining number of imports which must be checked before this unit can // be processed. int32_t imports_remaining = 0; // A list of incoming imports. This will be empty for `impl` files, because // imports only touch `api` files. llvm::SmallVector incoming_imports; // The corresponding `api` unit if this is an `impl` file. The entry should // also be in the corresponding `PackageImports`. UnitAndImports* api_for_impl = nullptr; // Whether the unit has been checked. bool is_checked = false; }; // Handles checking of a single unit. Requires that all dependencies have been // checked. // // This mainly splits out the single-unit logic from the higher level cross-unit // logic in check.cpp. class CheckUnit { public: explicit CheckUnit(UnitAndImports* unit_and_imports, int total_ir_count, llvm::IntrusiveRefCntPtr fs, llvm::raw_ostream* vlog_stream); // Produces and checks the IR for the provided unit. auto Run() -> void; private: // Add imports to the root block. auto InitPackageScopeAndImports() -> void; // Collects direct imports, for CollectTransitiveImports. auto CollectDirectImports(llvm::SmallVector& results, llvm::MutableArrayRef ir_to_result_index, SemIR::InstId import_decl_id, const PackageImports& imports, bool is_local) -> void; // Collects transitive imports, handling deduplication. These will be unified // between local_imports and api_imports. auto CollectTransitiveImports(SemIR::InstId import_decl_id, const PackageImports* local_imports, const PackageImports* api_imports) -> llvm::SmallVector; // Imports the current package. auto ImportCurrentPackage(SemIR::InstId package_inst_id, SemIR::TypeId namespace_type_id) -> void; // Imports all other Carbon packages (excluding the current package). auto ImportOtherPackages(SemIR::TypeId namespace_type_id) -> void; // Imports all C++ packages. auto ImportCppPackages() -> void; // Checks that each required definition is available. If the definition can be // generated by resolving a specific, does so, otherwise emits a diagnostic // for each declaration in context.definitions_required() that doesn't have a // definition. auto CheckRequiredDefinitions() -> void; // Loops over all nodes in the tree. On some errors, this may return early, // for example if an unrecoverable state is encountered. // NOLINTNEXTLINE(readability-function-size) auto ProcessNodeIds() -> bool; UnitAndImports* unit_and_imports_; // The number of IRs being checked in total. int total_ir_count_; llvm::IntrusiveRefCntPtr fs_; llvm::raw_ostream* vlog_stream_; Context::DiagnosticEmitter emitter_; Context context_; }; } // namespace Carbon::Check #endif // CARBON_TOOLCHAIN_CHECK_CHECK_UNIT_H_