check_unit.cpp 21 KB

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