check_unit.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  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. #include "toolchain/check/check_unit.h"
  5. #include <string>
  6. #include "llvm/ADT/IntrusiveRefCntPtr.h"
  7. #include "llvm/ADT/StringRef.h"
  8. #include "llvm/Support/VirtualFileSystem.h"
  9. #include "toolchain/base/kind_switch.h"
  10. #include "toolchain/base/pretty_stack_trace_function.h"
  11. #include "toolchain/check/generic.h"
  12. #include "toolchain/check/handle.h"
  13. #include "toolchain/check/impl.h"
  14. #include "toolchain/check/import.h"
  15. #include "toolchain/check/import_cpp.h"
  16. #include "toolchain/check/import_ref.h"
  17. #include "toolchain/check/inst.h"
  18. #include "toolchain/check/node_id_traversal.h"
  19. #include "toolchain/check/type.h"
  20. namespace Carbon::Check {
  21. // Returns the number of imported IRs, to assist in Context construction.
  22. static auto GetImportedIRCount(UnitAndImports* unit_and_imports) -> int {
  23. int count = 0;
  24. for (auto& package_imports : unit_and_imports->package_imports) {
  25. count += package_imports.imports.size();
  26. }
  27. if (!unit_and_imports->api_for_impl) {
  28. // Leave an empty slot for ImportIRId::ApiForImpl.
  29. ++count;
  30. }
  31. return count;
  32. }
  33. CheckUnit::CheckUnit(
  34. UnitAndImports* unit_and_imports,
  35. llvm::ArrayRef<Parse::GetTreeAndSubtreesFn> tree_and_subtrees_getters,
  36. llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
  37. llvm::raw_ostream* vlog_stream)
  38. : unit_and_imports_(unit_and_imports),
  39. total_ir_count_(tree_and_subtrees_getters.size()),
  40. fs_(std::move(fs)),
  41. vlog_stream_(vlog_stream),
  42. emitter_(&unit_and_imports_->err_tracker, tree_and_subtrees_getters,
  43. unit_and_imports_->unit->sem_ir),
  44. context_(&emitter_, unit_and_imports_->unit->tree_and_subtrees_getter,
  45. unit_and_imports_->unit->sem_ir,
  46. GetImportedIRCount(unit_and_imports),
  47. tree_and_subtrees_getters.size(), vlog_stream) {}
  48. auto CheckUnit::Run() -> void {
  49. Timings::ScopedTiming timing(unit_and_imports_->unit->timings, "check");
  50. // We can safely mark this as checked at the start.
  51. unit_and_imports_->is_checked = true;
  52. PrettyStackTraceFunction context_dumper(
  53. [&](llvm::raw_ostream& output) { context_.PrintForStackDump(output); });
  54. // Add a block for the file.
  55. context_.inst_block_stack().Push();
  56. InitPackageScopeAndImports();
  57. // Eagerly import the impls declared in the api file to prepare to redeclare
  58. // them.
  59. ImportImplsFromApiFile(context_);
  60. if (!ProcessNodeIds()) {
  61. context_.sem_ir().set_has_errors(true);
  62. return;
  63. }
  64. CheckRequiredDefinitions();
  65. context_.Finalize();
  66. context_.VerifyOnFinish();
  67. context_.sem_ir().set_has_errors(unit_and_imports_->err_tracker.seen_error());
  68. #ifndef NDEBUG
  69. if (auto verify = context_.sem_ir().Verify(); !verify.ok()) {
  70. CARBON_FATAL("{0}Built invalid semantics IR: {1}\n", context_.sem_ir(),
  71. verify.error());
  72. }
  73. #endif
  74. }
  75. auto CheckUnit::InitPackageScopeAndImports() -> void {
  76. // Importing makes many namespaces, so only canonicalize the type once.
  77. auto namespace_type_id =
  78. GetSingletonType(context_, SemIR::NamespaceType::SingletonInstId);
  79. // Define the package scope, with an instruction for `package` expressions to
  80. // reference.
  81. auto package_scope_id = context_.name_scopes().Add(
  82. SemIR::Namespace::PackageInstId, SemIR::NameId::PackageNamespace,
  83. SemIR::NameScopeId::None);
  84. CARBON_CHECK(package_scope_id == SemIR::NameScopeId::Package);
  85. auto package_inst_id =
  86. AddInst<SemIR::Namespace>(context_, Parse::NodeId::None,
  87. {.type_id = namespace_type_id,
  88. .name_scope_id = SemIR::NameScopeId::Package,
  89. .import_id = SemIR::InstId::None});
  90. CARBON_CHECK(package_inst_id == SemIR::Namespace::PackageInstId);
  91. // If there is an implicit `api` import, set it first so that it uses the
  92. // ImportIRId::ApiForImpl when processed for imports.
  93. if (unit_and_imports_->api_for_impl) {
  94. const auto& names = context_.parse_tree().packaging_decl()->names;
  95. auto import_decl_id = AddInst<SemIR::ImportDecl>(
  96. context_, names.node_id,
  97. {.package_id = SemIR::NameId::ForPackageName(names.package_id)});
  98. SetApiImportIR(context_,
  99. {.decl_id = import_decl_id,
  100. .is_export = false,
  101. .sem_ir = unit_and_imports_->api_for_impl->unit->sem_ir});
  102. } else {
  103. SetApiImportIR(context_,
  104. {.decl_id = SemIR::InstId::None, .sem_ir = nullptr});
  105. }
  106. // Add import instructions for everything directly imported. Implicit imports
  107. // are handled separately.
  108. for (auto& package_imports : unit_and_imports_->package_imports) {
  109. CARBON_CHECK(!package_imports.import_decl_id.has_value());
  110. package_imports.import_decl_id = AddInst<SemIR::ImportDecl>(
  111. context_, package_imports.node_id,
  112. {.package_id =
  113. SemIR::NameId::ForPackageName(package_imports.package_id)});
  114. }
  115. // Process the imports.
  116. if (unit_and_imports_->api_for_impl) {
  117. ImportApiFile(context_, namespace_type_id,
  118. *unit_and_imports_->api_for_impl->unit->sem_ir);
  119. }
  120. ImportCurrentPackage(package_inst_id, namespace_type_id);
  121. CARBON_CHECK(context_.scope_stack().PeekIndex() == ScopeIndex::Package);
  122. ImportOtherPackages(namespace_type_id);
  123. ImportCppFiles(context_, unit_and_imports_->unit->sem_ir->filename(),
  124. unit_and_imports_->cpp_import_names, fs_);
  125. }
  126. auto CheckUnit::CollectDirectImports(
  127. llvm::SmallVector<SemIR::ImportIR>& results,
  128. llvm::MutableArrayRef<int> ir_to_result_index, SemIR::InstId import_decl_id,
  129. const PackageImports& imports, bool is_local) -> void {
  130. for (const auto& import : imports.imports) {
  131. const auto& direct_ir = *import.unit_info->unit->sem_ir;
  132. auto& index = ir_to_result_index[direct_ir.check_ir_id().index];
  133. if (index != -1) {
  134. // This should only happen when doing API imports for an implementation
  135. // file. Don't change the entry; is_export doesn't matter.
  136. continue;
  137. }
  138. index = results.size();
  139. results.push_back({.decl_id = import_decl_id,
  140. // Only tag exports in API files, ignoring the value in
  141. // implementation files.
  142. .is_export = is_local && import.names.is_export,
  143. .sem_ir = &direct_ir});
  144. }
  145. }
  146. auto CheckUnit::CollectTransitiveImports(SemIR::InstId import_decl_id,
  147. const PackageImports* local_imports,
  148. const PackageImports* api_imports)
  149. -> llvm::SmallVector<SemIR::ImportIR> {
  150. llvm::SmallVector<SemIR::ImportIR> results;
  151. // Track whether an IR was imported in full, including `export import`. This
  152. // distinguishes from IRs that are indirectly added without all names being
  153. // exported to this IR.
  154. llvm::SmallVector<int> ir_to_result_index(total_ir_count_, -1);
  155. // First add direct imports. This means that if an entity is imported both
  156. // directly and indirectly, the import path will reflect the direct import.
  157. if (local_imports) {
  158. CollectDirectImports(results, ir_to_result_index, import_decl_id,
  159. *local_imports,
  160. /*is_local=*/true);
  161. }
  162. if (api_imports) {
  163. CollectDirectImports(results, ir_to_result_index, import_decl_id,
  164. *api_imports,
  165. /*is_local=*/false);
  166. }
  167. // Loop through direct imports for any indirect exports. The underlying vector
  168. // is appended during iteration, so take the size first.
  169. const int direct_imports = results.size();
  170. for (int direct_index : llvm::seq(direct_imports)) {
  171. bool is_export = results[direct_index].is_export;
  172. for (const auto& indirect_ir :
  173. results[direct_index].sem_ir->import_irs().array_ref()) {
  174. if (!indirect_ir.is_export) {
  175. continue;
  176. }
  177. auto& indirect_index =
  178. ir_to_result_index[indirect_ir.sem_ir->check_ir_id().index];
  179. if (indirect_index == -1) {
  180. indirect_index = results.size();
  181. // TODO: In the case of a recursive `export import`, this only points at
  182. // the outermost import. May want something that better reflects the
  183. // recursion.
  184. results.push_back({.decl_id = results[direct_index].decl_id,
  185. .is_export = is_export,
  186. .sem_ir = indirect_ir.sem_ir});
  187. } else if (is_export) {
  188. results[indirect_index].is_export = true;
  189. }
  190. }
  191. }
  192. return results;
  193. }
  194. auto CheckUnit::ImportCurrentPackage(SemIR::InstId package_inst_id,
  195. SemIR::TypeId namespace_type_id) -> void {
  196. // Add imports from the current package.
  197. auto import_map_lookup =
  198. unit_and_imports_->package_imports_map.Lookup(PackageNameId::None);
  199. if (!import_map_lookup) {
  200. // Push the scope; there are no names to add.
  201. context_.scope_stack().Push(package_inst_id, SemIR::NameScopeId::Package);
  202. return;
  203. }
  204. PackageImports& self_import =
  205. unit_and_imports_->package_imports[import_map_lookup.value()];
  206. if (self_import.has_load_error) {
  207. context_.name_scopes().Get(SemIR::NameScopeId::Package).set_has_error();
  208. }
  209. ImportLibrariesFromCurrentPackage(
  210. context_, namespace_type_id,
  211. CollectTransitiveImports(self_import.import_decl_id, &self_import,
  212. /*api_imports=*/nullptr));
  213. context_.scope_stack().Push(
  214. package_inst_id, SemIR::NameScopeId::Package, SemIR::SpecificId::None,
  215. context_.name_scopes().Get(SemIR::NameScopeId::Package).has_error());
  216. }
  217. auto CheckUnit::ImportOtherPackages(SemIR::TypeId namespace_type_id) -> void {
  218. // api_imports_list is initially the size of the current file's imports,
  219. // including for API files, for simplicity in iteration. It's only really used
  220. // when processing an implementation file, in order to combine the API file
  221. // imports.
  222. //
  223. // For packages imported by the API file, the PackageNameId is the package
  224. // name and the index is into the API's import list. Otherwise, the initial
  225. // {None, -1} state remains.
  226. llvm::SmallVector<std::pair<PackageNameId, int32_t>> api_imports_list;
  227. api_imports_list.resize(unit_and_imports_->package_imports.size(),
  228. {PackageNameId::None, -1});
  229. // When there's an API file, add the mapping to api_imports_list.
  230. if (unit_and_imports_->api_for_impl) {
  231. const auto& api_identifiers =
  232. unit_and_imports_->api_for_impl->unit->value_stores->identifiers();
  233. auto& impl_identifiers =
  234. unit_and_imports_->unit->value_stores->identifiers();
  235. for (auto [api_imports_index, api_imports] :
  236. llvm::enumerate(unit_and_imports_->api_for_impl->package_imports)) {
  237. // Skip the current package.
  238. if (!api_imports.package_id.has_value()) {
  239. continue;
  240. }
  241. // Translate the package ID from the API file to the implementation file.
  242. auto impl_package_id = api_imports.package_id;
  243. if (auto package_identifier_id = impl_package_id.AsIdentifierId();
  244. package_identifier_id.has_value()) {
  245. impl_package_id = PackageNameId::ForIdentifier(
  246. impl_identifiers.Add(api_identifiers.Get(package_identifier_id)));
  247. }
  248. if (auto lookup =
  249. unit_and_imports_->package_imports_map.Lookup(impl_package_id)) {
  250. // On a hit, replace the entry to unify the API and implementation
  251. // imports.
  252. api_imports_list[lookup.value()] = {impl_package_id, api_imports_index};
  253. } else {
  254. // On a miss, add the package as API-only.
  255. api_imports_list.push_back({impl_package_id, api_imports_index});
  256. }
  257. }
  258. }
  259. for (auto [i, api_imports_entry] : llvm::enumerate(api_imports_list)) {
  260. // These variables are updated after figuring out which imports are present.
  261. auto import_decl_id = SemIR::InstId::None;
  262. PackageNameId package_id = PackageNameId::None;
  263. bool has_load_error = false;
  264. // Identify the local package imports if present.
  265. PackageImports* local_imports = nullptr;
  266. if (i < unit_and_imports_->package_imports.size()) {
  267. local_imports = &unit_and_imports_->package_imports[i];
  268. if (!local_imports->package_id.has_value()) {
  269. // Skip the current package.
  270. continue;
  271. }
  272. import_decl_id = local_imports->import_decl_id;
  273. package_id = local_imports->package_id;
  274. has_load_error |= local_imports->has_load_error;
  275. }
  276. // Identify the API package imports if present.
  277. PackageImports* api_imports = nullptr;
  278. if (api_imports_entry.second != -1) {
  279. api_imports = &unit_and_imports_->api_for_impl
  280. ->package_imports[api_imports_entry.second];
  281. if (local_imports) {
  282. CARBON_CHECK(package_id == api_imports_entry.first);
  283. } else {
  284. auto import_ir_inst_id = context_.import_ir_insts().Add(
  285. {.ir_id = SemIR::ImportIRId::ApiForImpl,
  286. .inst_id = api_imports->import_decl_id});
  287. import_decl_id =
  288. AddInst(context_, MakeImportedLocIdAndInst<SemIR::ImportDecl>(
  289. context_, import_ir_inst_id,
  290. {.package_id = SemIR::NameId::ForPackageName(
  291. api_imports_entry.first)}));
  292. package_id = api_imports_entry.first;
  293. }
  294. has_load_error |= api_imports->has_load_error;
  295. }
  296. // Do the actual import.
  297. ImportLibrariesFromOtherPackage(
  298. context_, namespace_type_id, import_decl_id, package_id,
  299. CollectTransitiveImports(import_decl_id, local_imports, api_imports),
  300. has_load_error);
  301. }
  302. }
  303. // Loops over all nodes in the tree. On some errors, this may return early,
  304. // for example if an unrecoverable state is encountered.
  305. // NOLINTNEXTLINE(readability-function-size)
  306. auto CheckUnit::ProcessNodeIds() -> bool {
  307. NodeIdTraversal traversal(context_, vlog_stream_);
  308. Parse::NodeId node_id = Parse::NodeId::None;
  309. // On crash, report which token we were handling.
  310. PrettyStackTraceFunction node_dumper([&](llvm::raw_ostream& output) {
  311. const auto& tree = unit_and_imports_->unit->tree_and_subtrees_getter();
  312. auto converted = tree.NodeToDiagnosticLoc(node_id, /*token_only=*/false);
  313. converted.loc.FormatLocation(output);
  314. output << "checking " << context_.parse_tree().node_kind(node_id) << "\n";
  315. // Crash output has a tab indent; try to indent slightly past that.
  316. converted.loc.FormatSnippet(output, /*indent=*/10);
  317. });
  318. while (auto maybe_node_id = traversal.Next()) {
  319. node_id = *maybe_node_id;
  320. emitter_.AdvanceToken(context_.parse_tree().node_token(node_id));
  321. if (context_.parse_tree().node_has_error(node_id)) {
  322. context_.TODO(node_id, "handle invalid parse trees in `check`");
  323. return false;
  324. }
  325. bool result;
  326. auto parse_kind = context_.parse_tree().node_kind(node_id);
  327. switch (parse_kind) {
  328. #define CARBON_PARSE_NODE_KIND(Name) \
  329. case Parse::NodeKind::Name: { \
  330. result = HandleParseNode(context_, Parse::Name##Id(node_id)); \
  331. break; \
  332. }
  333. #include "toolchain/parse/node_kind.def"
  334. }
  335. if (!result) {
  336. CARBON_CHECK(
  337. unit_and_imports_->err_tracker.seen_error(),
  338. "HandleParseNode for `{0}` returned false without diagnosing.",
  339. parse_kind);
  340. return false;
  341. }
  342. traversal.Handle(parse_kind);
  343. }
  344. return true;
  345. }
  346. auto CheckUnit::CheckRequiredDefinitions() -> void {
  347. CARBON_DIAGNOSTIC(MissingDefinitionInImpl, Error,
  348. "no definition found for declaration in impl file");
  349. // Note that more required definitions can be added during this loop.
  350. for (size_t i = 0; i != context_.definitions_required().size(); ++i) {
  351. SemIR::InstId decl_inst_id = context_.definitions_required()[i];
  352. SemIR::Inst decl_inst = context_.insts().Get(decl_inst_id);
  353. CARBON_KIND_SWITCH(context_.insts().Get(decl_inst_id)) {
  354. case CARBON_KIND(SemIR::ClassDecl class_decl): {
  355. if (!context_.classes().Get(class_decl.class_id).is_defined()) {
  356. emitter_.Emit(decl_inst_id, MissingDefinitionInImpl);
  357. }
  358. break;
  359. }
  360. case CARBON_KIND(SemIR::FunctionDecl function_decl): {
  361. if (context_.functions().Get(function_decl.function_id).definition_id ==
  362. SemIR::InstId::None) {
  363. emitter_.Emit(decl_inst_id, MissingDefinitionInImpl);
  364. }
  365. break;
  366. }
  367. case CARBON_KIND(SemIR::ImplDecl impl_decl): {
  368. auto& impl = context_.impls().Get(impl_decl.impl_id);
  369. if (!impl.is_defined()) {
  370. FillImplWitnessWithErrors(context_, impl);
  371. CARBON_DIAGNOSTIC(ImplMissingDefinition, Error,
  372. "impl declared but not defined");
  373. emitter_.Emit(decl_inst_id, ImplMissingDefinition);
  374. }
  375. break;
  376. }
  377. case SemIR::InterfaceDecl::Kind: {
  378. // TODO: Handle `interface` as well, once we can test it without
  379. // triggering
  380. // https://github.com/carbon-language/carbon-lang/issues/4071.
  381. CARBON_FATAL("TODO: Support interfaces in DiagnoseMissingDefinitions");
  382. }
  383. case CARBON_KIND(SemIR::SpecificFunction specific_function): {
  384. // TODO: Track a location for the use. In general we may want to track a
  385. // list of enclosing locations if this was used from a generic.
  386. SemIRLoc use_loc = decl_inst_id;
  387. if (!ResolveSpecificDefinition(context_, use_loc,
  388. specific_function.specific_id)) {
  389. CARBON_DIAGNOSTIC(MissingGenericFunctionDefinition, Error,
  390. "use of undefined generic function");
  391. CARBON_DIAGNOSTIC(MissingGenericFunctionDefinitionHere, Note,
  392. "generic function declared here");
  393. auto generic_decl_id =
  394. context_.generics()
  395. .Get(context_.specifics()
  396. .Get(specific_function.specific_id)
  397. .generic_id)
  398. .decl_id;
  399. emitter_.Build(decl_inst_id, MissingGenericFunctionDefinition)
  400. .Note(generic_decl_id, MissingGenericFunctionDefinitionHere)
  401. .Emit();
  402. }
  403. break;
  404. }
  405. default: {
  406. CARBON_FATAL("Unexpected inst in definitions_required: {0}", decl_inst);
  407. }
  408. }
  409. }
  410. }
  411. } // namespace Carbon::Check