| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- // 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 "clang/Frontend/CompilerInvocation.h"
- #include "common/map.h"
- #include "llvm/ADT/SmallVector.h"
- #include "toolchain/check/check.h"
- #include "toolchain/check/context.h"
- #include "toolchain/check/diagnostic_emitter.h"
- #include "toolchain/parse/node_ids.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(PackageNameId package_id,
- Parse::AnyPackagingDeclId node_id)
- : package_id(package_id), node_id(node_id) {}
- // The identifier of the imported package.
- PackageNameId package_id;
- // The first `package` or `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::AnyPackagingDeclId 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<Import> imports;
- };
- // Contains information accumulated while checking a `Unit` (primarily import
- // information), in addition to the `Unit` itself.
- struct UnitAndImports {
- // Converts a `NodeId` to a diagnostic location for `UnitAndImports`.
- class NodeEmitter : public Diagnostics::Emitter<Parse::NodeId> {
- public:
- explicit NodeEmitter(Diagnostics::Consumer* consumer,
- Parse::GetTreeAndSubtreesFn tree_and_subtrees_getter)
- : Emitter(consumer),
- tree_and_subtrees_getter_(tree_and_subtrees_getter) {}
- protected:
- auto ConvertLoc(Parse::NodeId node_id, ContextFnT /*context_fn*/) const
- -> Diagnostics::ConvertedLoc override {
- return tree_and_subtrees_getter_().NodeToDiagnosticLoc(
- node_id, /*token_only=*/false);
- }
- private:
- Parse::GetTreeAndSubtreesFn tree_and_subtrees_getter_;
- };
- explicit UnitAndImports(Unit* unit,
- Parse::GetTreeAndSubtreesFn tree_and_subtrees_getter)
- : unit(unit),
- err_tracker(*unit->consumer),
- emitter(&err_tracker, tree_and_subtrees_getter) {}
- auto parse_tree() -> const Parse::Tree& { return unit->sem_ir->parse_tree(); }
- auto source() -> const SourceBuffer& {
- return parse_tree().tokens().source();
- }
- Unit* unit;
- // Emitter information.
- Diagnostics::ErrorTrackingConsumer err_tracker;
- NodeEmitter 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<PackageImports> package_imports;
- // A map of the package names to the outgoing imports above.
- Map<PackageNameId, int32_t> package_imports_map;
- // List of the `import Cpp` imports.
- llvm::SmallVector<Parse::Tree::PackagingNames> 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<UnitAndImports*> 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:
- // `unit_and_imports` and `tree_and_subtrees_getters` must be non-null.
- // `vlog_stream` is optional.
- explicit CheckUnit(
- UnitAndImports* unit_and_imports,
- const Parse::GetTreeAndSubtreesStore* tree_and_subtrees_getters,
- llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
- llvm::LLVMContext* llvm_context,
- std::shared_ptr<clang::CompilerInvocation> clang_invocation,
- llvm::raw_ostream* vlog_stream);
- // Produces and checks the IR for the provided unit.
- auto Run() -> void;
- private:
- using CheckIRIdToIntStore = FixedSizeValueStore<SemIR::CheckIRId, int>;
- // Add imports to the root block.
- auto InitPackageScopeAndImports() -> void;
- // Collects direct imports, for CollectTransitiveImports.
- auto CollectDirectImports(llvm::SmallVector<SemIR::ImportIR>& results,
- CheckIRIdToIntStore& 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<SemIR::ImportIR>;
- // 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;
- // Checks that each required declaration is available. This applies for
- // declarations that should exist in an owning library, for which an extern
- // declaration exists that assigns ownership to the current API.
- auto CheckRequiredDeclarations() -> 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_by_decl() and
- // context.definitions_required_by_use that doesn't have a definition.
- auto CheckRequiredDefinitions() -> void;
- // Re-run every impl lookup with a concrete result and make sure they find the
- // same witnesses.
- auto CheckPoisonedConcreteImplLookupQueries() -> void;
- // Look for `impl` declarations that are invalid.
- auto CheckImpls() -> void;
- // Does work after processing the parse tree, such as finishing the IR and
- // checking for missing contents.
- auto FinishRun() -> void;
- // Loops over all nodes in the tree. On some errors, this may return early,
- // for example if an unrecoverable state is encountered.
- auto ProcessNodeIds() -> bool;
- UnitAndImports* unit_and_imports_;
- Parse::GetTreeAndSubtreesFn tree_and_subtrees_getter_;
- llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs_;
- llvm::LLVMContext* llvm_context_;
- std::shared_ptr<clang::CompilerInvocation> clang_invocation_;
- DiagnosticEmitter emitter_;
- Context context_;
- };
- } // namespace Carbon::Check
- #endif // CARBON_TOOLCHAIN_CHECK_CHECK_UNIT_H_
|