check_unit.cpp 17 KB

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