check_unit.h 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef CARBON_TOOLCHAIN_CHECK_CHECK_UNIT_H_
  5. #define CARBON_TOOLCHAIN_CHECK_CHECK_UNIT_H_
  6. #include "clang/Frontend/CompilerInvocation.h"
  7. #include "common/map.h"
  8. #include "llvm/ADT/SmallVector.h"
  9. #include "toolchain/check/check.h"
  10. #include "toolchain/check/context.h"
  11. #include "toolchain/check/diagnostic_emitter.h"
  12. #include "toolchain/parse/node_ids.h"
  13. #include "toolchain/sem_ir/ids.h"
  14. namespace Carbon::Check {
  15. struct UnitAndImports;
  16. // A file's imports corresponding to a single package, for
  17. // `UnitAndImports::package_imports`.
  18. struct PackageImports {
  19. // A given import within the file, with its destination.
  20. struct Import {
  21. Parse::Tree::PackagingNames names;
  22. UnitAndImports* unit_info;
  23. };
  24. // Use the constructor so that the SmallVector is only constructed
  25. // as-needed.
  26. explicit PackageImports(PackageNameId package_id,
  27. Parse::AnyPackagingDeclId node_id)
  28. : package_id(package_id), node_id(node_id) {}
  29. // The identifier of the imported package.
  30. PackageNameId package_id;
  31. // The first `package` or `import` declaration in the file, which declared the
  32. // package's identifier (even if the import failed). Used for associating
  33. // diagnostics not specific to a single import.
  34. Parse::AnyPackagingDeclId node_id;
  35. // The associated `import` instruction. Has a value after a file is checked.
  36. SemIR::InstId import_decl_id = SemIR::InstId::None;
  37. // Whether there's an import that failed to load.
  38. bool has_load_error = false;
  39. // The list of valid imports.
  40. llvm::SmallVector<Import> imports;
  41. };
  42. // Contains information accumulated while checking a `Unit` (primarily import
  43. // information), in addition to the `Unit` itself.
  44. struct UnitAndImports {
  45. // Converts a `NodeId` to a diagnostic location for `UnitAndImports`.
  46. class NodeEmitter : public Diagnostics::Emitter<Parse::NodeId> {
  47. public:
  48. explicit NodeEmitter(Diagnostics::Consumer* consumer,
  49. Parse::GetTreeAndSubtreesFn tree_and_subtrees_getter)
  50. : Emitter(consumer),
  51. tree_and_subtrees_getter_(tree_and_subtrees_getter) {}
  52. protected:
  53. auto ConvertLoc(Parse::NodeId node_id, ContextFnT /*context_fn*/) const
  54. -> Diagnostics::ConvertedLoc override {
  55. return tree_and_subtrees_getter_().NodeToDiagnosticLoc(
  56. node_id, /*token_only=*/false);
  57. }
  58. private:
  59. Parse::GetTreeAndSubtreesFn tree_and_subtrees_getter_;
  60. };
  61. explicit UnitAndImports(Unit* unit,
  62. Parse::GetTreeAndSubtreesFn tree_and_subtrees_getter)
  63. : unit(unit),
  64. err_tracker(*unit->consumer),
  65. emitter(&err_tracker, tree_and_subtrees_getter) {}
  66. auto parse_tree() -> const Parse::Tree& { return unit->sem_ir->parse_tree(); }
  67. auto source() -> const SourceBuffer& {
  68. return parse_tree().tokens().source();
  69. }
  70. Unit* unit;
  71. // Emitter information.
  72. Diagnostics::ErrorTrackingConsumer err_tracker;
  73. NodeEmitter emitter;
  74. // List of the outgoing imports. If a package includes unavailable library
  75. // imports, it has an entry with has_load_error set. Invalid imports (for
  76. // example, `import Main;`) aren't added because they won't add identifiers to
  77. // name lookup.
  78. llvm::SmallVector<PackageImports> package_imports;
  79. // A map of the package names to the outgoing imports above.
  80. Map<PackageNameId, int32_t> package_imports_map;
  81. // List of the `import Cpp` imports.
  82. llvm::SmallVector<Parse::Tree::PackagingNames> cpp_imports;
  83. // The remaining number of imports which must be checked before this unit can
  84. // be processed.
  85. int32_t imports_remaining = 0;
  86. // A list of incoming imports. This will be empty for `impl` files, because
  87. // imports only touch `api` files.
  88. llvm::SmallVector<UnitAndImports*> incoming_imports;
  89. // The corresponding `api` unit if this is an `impl` file. The entry should
  90. // also be in the corresponding `PackageImports`.
  91. UnitAndImports* api_for_impl = nullptr;
  92. // Whether the unit has been checked.
  93. bool is_checked = false;
  94. };
  95. // Handles checking of a single unit. Requires that all dependencies have been
  96. // checked.
  97. //
  98. // This mainly splits out the single-unit logic from the higher level cross-unit
  99. // logic in check.cpp.
  100. class CheckUnit {
  101. public:
  102. // `unit_and_imports` and `tree_and_subtrees_getters` must be non-null.
  103. // `vlog_stream` is optional.
  104. explicit CheckUnit(
  105. UnitAndImports* unit_and_imports,
  106. const Parse::GetTreeAndSubtreesStore* tree_and_subtrees_getters,
  107. llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
  108. std::shared_ptr<clang::CompilerInvocation> clang_invocation,
  109. llvm::raw_ostream* vlog_stream);
  110. // Produces and checks the IR for the provided unit.
  111. auto Run() -> void;
  112. private:
  113. using CheckIRIdToIntStore = FixedSizeValueStore<SemIR::CheckIRId, int>;
  114. // Add imports to the root block.
  115. auto InitPackageScopeAndImports() -> void;
  116. // Collects direct imports, for CollectTransitiveImports.
  117. auto CollectDirectImports(llvm::SmallVector<SemIR::ImportIR>& results,
  118. CheckIRIdToIntStore& ir_to_result_index,
  119. SemIR::InstId import_decl_id,
  120. const PackageImports& imports, bool is_local)
  121. -> void;
  122. // Collects transitive imports, handling deduplication. These will be unified
  123. // between local_imports and api_imports.
  124. auto CollectTransitiveImports(SemIR::InstId import_decl_id,
  125. const PackageImports* local_imports,
  126. const PackageImports* api_imports)
  127. -> llvm::SmallVector<SemIR::ImportIR>;
  128. // Imports the current package.
  129. auto ImportCurrentPackage(SemIR::InstId package_inst_id,
  130. SemIR::TypeId namespace_type_id) -> void;
  131. // Imports all other Carbon packages (excluding the current package).
  132. auto ImportOtherPackages(SemIR::TypeId namespace_type_id) -> void;
  133. // Checks that each required declaration is available. This applies for
  134. // declarations that should exist in an owning library, for which an extern
  135. // declaration exists that assigns ownership to the current API.
  136. auto CheckRequiredDeclarations() -> void;
  137. // Checks that each required definition is available. If the definition can be
  138. // generated by resolving a specific, does so, otherwise emits a diagnostic
  139. // for each declaration in context.definitions_required_by_decl() and
  140. // context.definitions_required_by_use that doesn't have a definition.
  141. auto CheckRequiredDefinitions() -> void;
  142. // Re-run every impl lookup with a concrete result and make sure they find the
  143. // same witnesses.
  144. auto CheckPoisonedConcreteImplLookupQueries() -> void;
  145. // Look for `impl` declarations that are invalid.
  146. auto CheckImpls() -> void;
  147. // Does work after processing the parse tree, such as finishing the IR and
  148. // checking for missing contents.
  149. auto FinishRun() -> void;
  150. // Loops over all nodes in the tree. On some errors, this may return early,
  151. // for example if an unrecoverable state is encountered.
  152. // NOLINTNEXTLINE(readability-function-size)
  153. auto ProcessNodeIds() -> bool;
  154. UnitAndImports* unit_and_imports_;
  155. Parse::GetTreeAndSubtreesFn tree_and_subtrees_getter_;
  156. llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs_;
  157. std::shared_ptr<clang::CompilerInvocation> clang_invocation_;
  158. DiagnosticEmitter emitter_;
  159. Context context_;
  160. };
  161. } // namespace Carbon::Check
  162. #endif // CARBON_TOOLCHAIN_CHECK_CHECK_UNIT_H_