import_ref.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  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/import_ref.h"
  5. #include "common/check.h"
  6. #include "toolchain/check/context.h"
  7. #include "toolchain/check/eval.h"
  8. #include "toolchain/parse/node_ids.h"
  9. #include "toolchain/sem_ir/file.h"
  10. #include "toolchain/sem_ir/ids.h"
  11. #include "toolchain/sem_ir/inst.h"
  12. #include "toolchain/sem_ir/inst_kind.h"
  13. #include "toolchain/sem_ir/typed_insts.h"
  14. namespace Carbon::Check {
  15. // Resolves an instruction from an imported IR into a constant referring to the
  16. // current IR.
  17. //
  18. // Calling Resolve on an instruction operates in an iterative manner, tracking
  19. // Work items on work_stack_. At a high level, the loop is:
  20. //
  21. // 1. If Work has received a constant, it's considered resolved.
  22. // - If made_incomplete_type, resolve unconditionally.
  23. // - The constant check avoids performance costs of deduplication on add.
  24. // 2. Resolve the instruction: (TryResolveInst/TryResolveTypedInst)
  25. // - For most cases:
  26. // A. For types which _can_ be incomplete, when not made_incomplete_type:
  27. // i. Start by making an incomplete type to address circular references.
  28. // ii. If the imported type is incomplete, return the constant.
  29. // iii. Otherwise, set made_incomplete_type and continue resolving.
  30. // - Creating an incomplete type will have set the constant, which
  31. // influences step (1); setting made_incomplete_type gets us a second
  32. // resolve pass when needed.
  33. // B. Gather all input constants.
  34. // - Gathering constants directly adds unresolved values to work_stack_.
  35. // C. If any need to be resolved (HasNewWork), return Invalid; this
  36. // instruction needs two calls to complete.
  37. // D. Build any necessary IR structures, and return the output constant.
  38. // - For trivial cases with zero or one input constants, this may return
  39. // a constant (if one, potentially Invalid) directly.
  40. // 3. If resolving returned a non-Invalid constant, pop the work; otherwise, it
  41. // needs to remain (and may no longer be at the top of the stack).
  42. //
  43. // TryResolveInst/TryResolveTypedInst can complete in one call for a given
  44. // instruction, but should always complete within two calls. However, due to the
  45. // chance of a second call, it's important to reserve all expensive logic until
  46. // it's been established that input constants are available; this in particular
  47. // includes GetTypeIdForTypeConstant calls which do a hash table lookup.
  48. class ImportRefResolver {
  49. public:
  50. explicit ImportRefResolver(Context& context, SemIR::ImportIRId import_ir_id)
  51. : context_(context),
  52. import_ir_id_(import_ir_id),
  53. import_ir_(*context_.import_irs().Get(import_ir_id)),
  54. import_ir_constant_values_(
  55. context_.import_ir_constant_values()[import_ir_id.index]) {}
  56. // Iteratively resolves an imported instruction's inner references until a
  57. // constant ID referencing the current IR is produced. When an outer
  58. // instruction has unresolved inner references, it will add them to the stack
  59. // for inner evaluation and reattempt outer evaluation after.
  60. auto Resolve(SemIR::InstId inst_id) -> SemIR::ConstantId {
  61. work_stack_.push_back({inst_id});
  62. while (!work_stack_.empty()) {
  63. auto work = work_stack_.back();
  64. CARBON_CHECK(work.inst_id.is_valid());
  65. // Double-check that the constant still doesn't have a calculated value.
  66. // This should typically be checked before adding it, but a given
  67. // instruction may be added multiple times before its constant is
  68. // evaluated.
  69. if (!work.made_incomplete_type &&
  70. import_ir_constant_values_.Get(work.inst_id).is_valid()) {
  71. work_stack_.pop_back();
  72. } else if (auto new_const_id =
  73. TryResolveInst(work.inst_id, work.made_incomplete_type);
  74. new_const_id.is_valid()) {
  75. import_ir_constant_values_.Set(work.inst_id, new_const_id);
  76. work_stack_.pop_back();
  77. }
  78. }
  79. auto constant_id = import_ir_constant_values_.Get(inst_id);
  80. CARBON_CHECK(constant_id.is_valid());
  81. return constant_id;
  82. }
  83. // Wraps constant evaluation with logic to handle types.
  84. auto ResolveType(SemIR::TypeId import_type_id) -> SemIR::TypeId {
  85. if (!import_type_id.is_valid()) {
  86. return import_type_id;
  87. }
  88. auto import_type_inst_id = import_ir_.types().GetInstId(import_type_id);
  89. CARBON_CHECK(import_type_inst_id.is_valid());
  90. if (import_type_inst_id.is_builtin()) {
  91. // Builtins don't require constant resolution; we can use them directly.
  92. return context_.GetBuiltinType(import_type_inst_id.builtin_kind());
  93. } else {
  94. return context_.GetTypeIdForTypeConstant(Resolve(import_type_inst_id));
  95. }
  96. }
  97. private:
  98. // A step in work_stack_.
  99. struct Work {
  100. // The instruction to work on.
  101. SemIR::InstId inst_id;
  102. // True if a first pass made an incomplete type.
  103. bool made_incomplete_type = false;
  104. };
  105. // For imported entities, we use an invalid enclosing scope. This will be okay
  106. // if the scope isn't used later, but we may need to change logic for this if
  107. // the behavior changes.
  108. static constexpr SemIR::NameScopeId NoEnclosingScopeForImports =
  109. SemIR::NameScopeId::Invalid;
  110. // Returns true if new unresolved constants were found.
  111. //
  112. // At the start of a function, do:
  113. // auto initial_work = work_stack_.size();
  114. // Then when determining:
  115. // if (HasNewWork(initial_work)) { ... }
  116. auto HasNewWork(size_t initial_work) -> bool {
  117. CARBON_CHECK(initial_work <= work_stack_.size())
  118. << "Work shouldn't decrease";
  119. return initial_work < work_stack_.size();
  120. }
  121. // Returns the ConstantId for an InstId. Adds unresolved constants to
  122. // work_stack_.
  123. auto GetLocalConstantId(SemIR::InstId inst_id) -> SemIR::ConstantId {
  124. auto const_id = import_ir_constant_values_.Get(inst_id);
  125. if (!const_id.is_valid()) {
  126. work_stack_.push_back({inst_id});
  127. }
  128. return const_id;
  129. }
  130. // Returns the ConstantId for a TypeId. Adds unresolved constants to
  131. // work_stack_.
  132. auto GetLocalConstantId(SemIR::TypeId type_id) -> SemIR::ConstantId {
  133. return GetLocalConstantId(import_ir_.types().GetInstId(type_id));
  134. }
  135. // Returns the ConstantId for each parameter's type. Adds unresolved constants
  136. // to work_stack_.
  137. auto GetLocalParamConstantIds(SemIR::InstBlockId param_refs_id)
  138. -> llvm::SmallVector<SemIR::ConstantId> {
  139. if (param_refs_id == SemIR::InstBlockId::Empty) {
  140. return {};
  141. }
  142. const auto& param_refs = import_ir_.inst_blocks().Get(param_refs_id);
  143. llvm::SmallVector<SemIR::ConstantId> const_ids;
  144. const_ids.reserve(param_refs.size());
  145. for (auto inst_id : param_refs) {
  146. const_ids.push_back(
  147. GetLocalConstantId(import_ir_.insts().Get(inst_id).type_id()));
  148. }
  149. return const_ids;
  150. }
  151. // Given a param_refs_id and const_ids from GetLocalParamConstantIds, returns
  152. // a version of param_refs_id localized to the current IR.
  153. auto GetLocalParamRefsId(
  154. SemIR::InstBlockId param_refs_id,
  155. const llvm::SmallVector<SemIR::ConstantId>& const_ids)
  156. -> SemIR::InstBlockId {
  157. if (param_refs_id == SemIR::InstBlockId::Empty) {
  158. return SemIR::InstBlockId::Empty;
  159. }
  160. const auto& param_refs = import_ir_.inst_blocks().Get(param_refs_id);
  161. llvm::SmallVector<SemIR::InstId> new_param_refs;
  162. for (auto [ref_id, const_id] : llvm::zip(param_refs, const_ids)) {
  163. // Figure out the param structure. This echoes
  164. // Function::GetParamFromParamRefId.
  165. // TODO: Consider a different parameter handling to simplify import logic.
  166. auto inst = import_ir_.insts().Get(ref_id);
  167. auto addr_inst = inst.TryAs<SemIR::AddrPattern>();
  168. if (addr_inst) {
  169. inst = import_ir_.insts().Get(addr_inst->inner_id);
  170. }
  171. auto bind_inst = inst.TryAs<SemIR::AnyBindName>();
  172. if (bind_inst) {
  173. inst = import_ir_.insts().Get(bind_inst->value_id);
  174. }
  175. auto param_inst = inst.As<SemIR::Param>();
  176. // Rebuild the param instruction.
  177. auto name_id = GetLocalNameId(param_inst.name_id);
  178. auto type_id = context_.GetTypeIdForTypeConstant(const_id);
  179. auto new_param_id = context_.AddInstInNoBlock(
  180. {Parse::NodeId::Invalid, SemIR::Param{type_id, name_id}});
  181. if (bind_inst) {
  182. auto bind_name_id = context_.bind_names().Add(
  183. {.name_id = name_id,
  184. .enclosing_scope_id = SemIR::NameScopeId::Invalid});
  185. switch (bind_inst->kind) {
  186. case SemIR::InstKind::BindName:
  187. new_param_id = context_.AddInstInNoBlock(
  188. {Parse::NodeId::Invalid,
  189. SemIR::BindName{type_id, bind_name_id, new_param_id}});
  190. break;
  191. case SemIR::InstKind::BindSymbolicName:
  192. new_param_id = context_.AddInstInNoBlock(
  193. {Parse::NodeId::Invalid,
  194. SemIR::BindSymbolicName{type_id, bind_name_id, new_param_id}});
  195. break;
  196. default:
  197. CARBON_FATAL() << "Unexpected kind: " << bind_inst->kind;
  198. }
  199. }
  200. if (addr_inst) {
  201. new_param_id = context_.AddInstInNoBlock(
  202. {Parse::NodeId::Invalid,
  203. SemIR::AddrPattern{type_id, new_param_id}});
  204. }
  205. new_param_refs.push_back(new_param_id);
  206. }
  207. return context_.inst_blocks().Add(new_param_refs);
  208. }
  209. // Translates a NameId from the import IR to a local NameId.
  210. auto GetLocalNameId(SemIR::NameId import_name_id) -> SemIR::NameId {
  211. if (auto ident_id = import_name_id.AsIdentifierId(); ident_id.is_valid()) {
  212. return SemIR::NameId::ForIdentifier(
  213. context_.identifiers().Add(import_ir_.identifiers().Get(ident_id)));
  214. }
  215. return import_name_id;
  216. }
  217. // Tries to resolve the InstId, returning a constant when ready, or Invalid if
  218. // more has been added to the stack. A similar API is followed for all
  219. // following TryResolveTypedInst helper functions.
  220. //
  221. // TODO: Error is returned when support is missing, but that should go away.
  222. auto TryResolveInst(SemIR::InstId inst_id, bool made_incomplete_type)
  223. -> SemIR::ConstantId {
  224. if (inst_id.is_builtin()) {
  225. CARBON_CHECK(!made_incomplete_type);
  226. // Constants for builtins can be directly copied.
  227. return context_.constant_values().Get(inst_id);
  228. }
  229. auto inst = import_ir_.insts().Get(inst_id);
  230. CARBON_CHECK(!made_incomplete_type ||
  231. inst.kind() == SemIR::InstKind::ClassDecl)
  232. << "Currently only decls with incomplete types should need "
  233. "made_incomplete_type states: "
  234. << inst.kind();
  235. switch (inst.kind()) {
  236. case SemIR::InstKind::BaseDecl:
  237. return TryResolveTypedInst(inst.As<SemIR::BaseDecl>());
  238. case SemIR::InstKind::BindAlias:
  239. return TryResolveTypedInst(inst.As<SemIR::BindAlias>());
  240. case SemIR::InstKind::ClassDecl:
  241. return TryResolveTypedInst(inst.As<SemIR::ClassDecl>(), inst_id,
  242. made_incomplete_type);
  243. case SemIR::InstKind::ClassType:
  244. return TryResolveTypedInst(inst.As<SemIR::ClassType>());
  245. case SemIR::InstKind::ConstType:
  246. return TryResolveTypedInst(inst.As<SemIR::ConstType>());
  247. case SemIR::InstKind::FieldDecl:
  248. return TryResolveTypedInst(inst.As<SemIR::FieldDecl>());
  249. case SemIR::InstKind::FunctionDecl:
  250. return TryResolveTypedInst(inst.As<SemIR::FunctionDecl>());
  251. case SemIR::InstKind::PointerType:
  252. return TryResolveTypedInst(inst.As<SemIR::PointerType>());
  253. case SemIR::InstKind::StructType:
  254. return TryResolveTypedInst(inst.As<SemIR::StructType>());
  255. case SemIR::InstKind::TupleType:
  256. return TryResolveTypedInst(inst.As<SemIR::TupleType>());
  257. case SemIR::InstKind::UnboundElementType:
  258. return TryResolveTypedInst(inst.As<SemIR::UnboundElementType>());
  259. case SemIR::InstKind::BindName:
  260. case SemIR::InstKind::BindSymbolicName:
  261. // Can use TryEvalInst because the resulting constant doesn't really use
  262. // `inst`.
  263. return TryEvalInst(context_, inst_id, inst);
  264. case SemIR::InstKind::InterfaceDecl:
  265. // TODO: Not implemented.
  266. return SemIR::ConstantId::Error;
  267. default:
  268. context_.TODO(
  269. Parse::NodeId::Invalid,
  270. llvm::formatv("TryResolveInst on {0}", inst.kind()).str());
  271. return SemIR::ConstantId::Error;
  272. }
  273. }
  274. auto TryResolveTypedInst(SemIR::BaseDecl inst) -> SemIR::ConstantId {
  275. auto initial_work = work_stack_.size();
  276. auto type_const_id = GetLocalConstantId(inst.type_id);
  277. auto base_type_const_id = GetLocalConstantId(inst.base_type_id);
  278. if (HasNewWork(initial_work)) {
  279. return SemIR::ConstantId::Invalid;
  280. }
  281. // Import the instruction in order to update contained base_type_id.
  282. auto inst_id = context_.AddInstInNoBlock(
  283. {Parse::NodeId::Invalid,
  284. SemIR::BaseDecl{context_.GetTypeIdForTypeConstant(type_const_id),
  285. context_.GetTypeIdForTypeConstant(base_type_const_id),
  286. inst.index}});
  287. return context_.constant_values().Get(inst_id);
  288. }
  289. auto TryResolveTypedInst(SemIR::BindAlias inst) -> SemIR::ConstantId {
  290. auto initial_work = work_stack_.size();
  291. auto value_id = GetLocalConstantId(inst.value_id);
  292. if (HasNewWork(initial_work)) {
  293. return SemIR::ConstantId::Invalid;
  294. }
  295. return value_id;
  296. }
  297. // Makes an incomplete class. This is necessary even with classes with a
  298. // complete declaration, because things such as `Self` may refer back to the
  299. // type.
  300. auto MakeIncompleteClass(SemIR::InstId inst_id,
  301. const SemIR::Class& import_class)
  302. -> SemIR::ConstantId {
  303. auto class_decl =
  304. SemIR::ClassDecl{SemIR::TypeId::Invalid, SemIR::ClassId::Invalid,
  305. SemIR::InstBlockId::Empty};
  306. auto class_decl_id =
  307. context_.AddPlaceholderInst({Parse::NodeId::Invalid, class_decl});
  308. // Regardless of whether ClassDecl is a complete type, we first need an
  309. // incomplete type so that any references have something to point at.
  310. class_decl.class_id = context_.classes().Add({
  311. .name_id = GetLocalNameId(import_class.name_id),
  312. .enclosing_scope_id = NoEnclosingScopeForImports,
  313. // `.self_type_id` depends on the ClassType, so is set below.
  314. .self_type_id = SemIR::TypeId::Invalid,
  315. .decl_id = class_decl_id,
  316. .inheritance_kind = import_class.inheritance_kind,
  317. });
  318. // Write the function ID into the ClassDecl.
  319. context_.ReplaceInstBeforeConstantUse(class_decl_id,
  320. {Parse::NodeId::Invalid, class_decl});
  321. auto self_const_id = context_.constant_values().Get(class_decl_id);
  322. // Build the `Self` type using the resulting type constant.
  323. auto& class_info = context_.classes().Get(class_decl.class_id);
  324. class_info.self_type_id = context_.GetTypeIdForTypeConstant(self_const_id);
  325. // Set a constant corresponding to the incomplete class.
  326. import_ir_constant_values_.Set(inst_id, self_const_id);
  327. return self_const_id;
  328. }
  329. // Fills out the class definition for an incomplete class.
  330. auto AddClassDefinition(const SemIR::Class& import_class,
  331. SemIR::ConstantId class_const_id,
  332. SemIR::ConstantId object_repr_const_id,
  333. SemIR::ConstantId base_const_id) -> void {
  334. auto& new_class = context_.classes().Get(
  335. context_.insts()
  336. .GetAs<SemIR::ClassType>(class_const_id.inst_id())
  337. .class_id);
  338. new_class.object_repr_id =
  339. context_.GetTypeIdForTypeConstant(object_repr_const_id);
  340. new_class.scope_id =
  341. context_.name_scopes().Add(new_class.decl_id, SemIR::NameId::Invalid,
  342. new_class.enclosing_scope_id);
  343. auto& new_scope = context_.name_scopes().Get(new_class.scope_id);
  344. const auto& old_scope = import_ir_.name_scopes().Get(import_class.scope_id);
  345. // Push a block so that we can add scoped instructions to it, primarily for
  346. // textual IR formatting.
  347. context_.inst_block_stack().Push();
  348. for (auto [entry_name_id, entry_inst_id] : old_scope.names) {
  349. CARBON_CHECK(
  350. new_scope.names
  351. .insert({GetLocalNameId(entry_name_id),
  352. context_.AddPlaceholderInst(SemIR::ImportRefUnused{
  353. import_ir_id_, entry_inst_id})})
  354. .second);
  355. }
  356. new_class.body_block_id = context_.inst_block_stack().Pop();
  357. if (import_class.base_id.is_valid()) {
  358. new_class.base_id = base_const_id.inst_id();
  359. // Add the base scope to extended scopes.
  360. auto base_inst_id = context_.types().GetInstId(
  361. context_.insts()
  362. .GetAs<SemIR::BaseDecl>(new_class.base_id)
  363. .base_type_id);
  364. const auto& base_class = context_.classes().Get(
  365. context_.insts().GetAs<SemIR::ClassType>(base_inst_id).class_id);
  366. new_scope.extended_scopes.push_back(base_class.scope_id);
  367. }
  368. CARBON_CHECK(new_scope.extended_scopes.size() ==
  369. old_scope.extended_scopes.size());
  370. }
  371. auto TryResolveTypedInst(SemIR::ClassDecl inst, SemIR::InstId inst_id,
  372. bool made_incomplete_type) -> SemIR::ConstantId {
  373. const auto& import_class = import_ir_.classes().Get(inst.class_id);
  374. SemIR::ConstantId class_const_id = SemIR::ConstantId::Invalid;
  375. // On the first pass, there's no incomplete type; start by adding one for
  376. // any recursive references.
  377. if (!made_incomplete_type) {
  378. class_const_id = MakeIncompleteClass(inst_id, import_class);
  379. // If there's only a forward declaration, we're done.
  380. if (!import_class.object_repr_id.is_valid()) {
  381. return class_const_id;
  382. }
  383. // This may not be needed because all constants might be ready, but we do
  384. // it here so that we don't need to track which work item corresponds to
  385. // this instruction.
  386. work_stack_.back().made_incomplete_type = true;
  387. }
  388. CARBON_CHECK(import_class.object_repr_id.is_valid())
  389. << "Only reachable when there's a definition.";
  390. // Load constants for the definition.
  391. auto initial_work = work_stack_.size();
  392. auto object_repr_const_id = GetLocalConstantId(import_class.object_repr_id);
  393. auto base_const_id = import_class.base_id.is_valid()
  394. ? GetLocalConstantId(import_class.base_id)
  395. : SemIR::ConstantId::Invalid;
  396. if (HasNewWork(initial_work)) {
  397. return SemIR::ConstantId::Invalid;
  398. }
  399. // On the first pass, we build the incomplete type's constant above. If we
  400. // get here on a subsequent pass we need to fetch the one we built in the
  401. // first pass.
  402. if (made_incomplete_type) {
  403. CARBON_CHECK(!class_const_id.is_valid())
  404. << "Shouldn't have a const yet when resuming";
  405. class_const_id = import_ir_constant_values_.Get(inst_id);
  406. }
  407. AddClassDefinition(import_class, class_const_id, object_repr_const_id,
  408. base_const_id);
  409. return class_const_id;
  410. }
  411. auto TryResolveTypedInst(SemIR::ClassType inst) -> SemIR::ConstantId {
  412. CARBON_CHECK(inst.type_id == SemIR::TypeId::TypeType);
  413. // ClassType uses a straight reference to the constant ID generated as part
  414. // of pulling in the ClassDecl, so there's no need to phase logic.
  415. return GetLocalConstantId(import_ir_.classes().Get(inst.class_id).decl_id);
  416. }
  417. auto TryResolveTypedInst(SemIR::ConstType inst) -> SemIR::ConstantId {
  418. auto initial_work = work_stack_.size();
  419. CARBON_CHECK(inst.type_id == SemIR::TypeId::TypeType);
  420. auto inner_const_id = GetLocalConstantId(inst.inner_id);
  421. if (HasNewWork(initial_work)) {
  422. return SemIR::ConstantId::Invalid;
  423. }
  424. auto inner_type_id = context_.GetTypeIdForTypeConstant(inner_const_id);
  425. // TODO: Should ConstType have a wrapper for this similar to the others?
  426. return TryEvalInst(
  427. context_, SemIR::InstId::Invalid,
  428. SemIR::ConstType{SemIR::TypeId::TypeType, inner_type_id});
  429. }
  430. auto TryResolveTypedInst(SemIR::FieldDecl inst) -> SemIR::ConstantId {
  431. auto initial_work = work_stack_.size();
  432. auto const_id = GetLocalConstantId(inst.type_id);
  433. if (HasNewWork(initial_work)) {
  434. return SemIR::ConstantId::Invalid;
  435. }
  436. auto inst_id = context_.AddInstInNoBlock(
  437. {Parse::NodeId::Invalid,
  438. SemIR::FieldDecl{context_.GetTypeIdForTypeConstant(const_id),
  439. GetLocalNameId(inst.name_id), inst.index}});
  440. return context_.constant_values().Get(inst_id);
  441. }
  442. auto TryResolveTypedInst(SemIR::FunctionDecl inst) -> SemIR::ConstantId {
  443. auto initial_work = work_stack_.size();
  444. auto type_const_id = GetLocalConstantId(inst.type_id);
  445. const auto& function = import_ir_.functions().Get(inst.function_id);
  446. auto return_type_const_id = SemIR::ConstantId::Invalid;
  447. if (function.return_type_id.is_valid()) {
  448. return_type_const_id = GetLocalConstantId(function.return_type_id);
  449. }
  450. auto return_slot_const_id = SemIR::ConstantId::Invalid;
  451. if (function.return_slot_id.is_valid()) {
  452. return_slot_const_id = GetLocalConstantId(function.return_slot_id);
  453. }
  454. llvm::SmallVector<SemIR::ConstantId> implicit_param_const_ids =
  455. GetLocalParamConstantIds(function.implicit_param_refs_id);
  456. llvm::SmallVector<SemIR::ConstantId> param_const_ids =
  457. GetLocalParamConstantIds(function.param_refs_id);
  458. if (HasNewWork(initial_work)) {
  459. return SemIR::ConstantId::Invalid;
  460. }
  461. // Add the function declaration.
  462. auto function_decl =
  463. SemIR::FunctionDecl{context_.GetTypeIdForTypeConstant(type_const_id),
  464. SemIR::FunctionId::Invalid};
  465. auto function_decl_id = context_.AddPlaceholderInstInNoBlock(
  466. {Parse::NodeId::Invalid, function_decl});
  467. auto new_return_type_id =
  468. return_type_const_id.is_valid()
  469. ? context_.GetTypeIdForTypeConstant(return_type_const_id)
  470. : SemIR::TypeId::Invalid;
  471. auto new_return_slot = SemIR::InstId::Invalid;
  472. if (function.return_slot_id.is_valid()) {
  473. context_.AddInstInNoBlock({SemIR::ImportRefUsed{
  474. context_.GetTypeIdForTypeConstant(return_slot_const_id),
  475. import_ir_id_, function.return_slot_id}});
  476. }
  477. function_decl.function_id = context_.functions().Add(
  478. {.name_id = GetLocalNameId(function.name_id),
  479. .enclosing_scope_id = NoEnclosingScopeForImports,
  480. .decl_id = function_decl_id,
  481. .implicit_param_refs_id = GetLocalParamRefsId(
  482. function.implicit_param_refs_id, implicit_param_const_ids),
  483. .param_refs_id =
  484. GetLocalParamRefsId(function.param_refs_id, param_const_ids),
  485. .return_type_id = new_return_type_id,
  486. .return_slot_id = new_return_slot});
  487. // Write the function ID into the FunctionDecl.
  488. context_.ReplaceInstBeforeConstantUse(
  489. function_decl_id, {Parse::NodeId::Invalid, function_decl});
  490. return context_.constant_values().Get(function_decl_id);
  491. }
  492. auto TryResolveTypedInst(SemIR::PointerType inst) -> SemIR::ConstantId {
  493. auto initial_work = work_stack_.size();
  494. CARBON_CHECK(inst.type_id == SemIR::TypeId::TypeType);
  495. auto pointee_const_id = GetLocalConstantId(inst.pointee_id);
  496. if (HasNewWork(initial_work)) {
  497. return SemIR::ConstantId::Invalid;
  498. }
  499. auto pointee_type_id = context_.GetTypeIdForTypeConstant(pointee_const_id);
  500. return context_.types().GetConstantId(
  501. context_.GetPointerType(pointee_type_id));
  502. }
  503. auto TryResolveTypedInst(SemIR::StructType inst) -> SemIR::ConstantId {
  504. // Collect all constants first, locating unresolved ones in a single pass.
  505. auto initial_work = work_stack_.size();
  506. CARBON_CHECK(inst.type_id == SemIR::TypeId::TypeType);
  507. auto orig_fields = import_ir_.inst_blocks().Get(inst.fields_id);
  508. llvm::SmallVector<SemIR::ConstantId> field_const_ids;
  509. field_const_ids.reserve(orig_fields.size());
  510. for (auto field_id : orig_fields) {
  511. auto field = import_ir_.insts().GetAs<SemIR::StructTypeField>(field_id);
  512. field_const_ids.push_back(GetLocalConstantId(field.field_type_id));
  513. }
  514. if (HasNewWork(initial_work)) {
  515. return SemIR::ConstantId::Invalid;
  516. }
  517. // Prepare a vector of fields for GetStructType.
  518. // TODO: Should we have field constants so that we can deduplicate fields
  519. // without creating instructions here?
  520. llvm::SmallVector<SemIR::InstId> fields;
  521. fields.reserve(orig_fields.size());
  522. for (auto [field_id, field_const_id] :
  523. llvm::zip(orig_fields, field_const_ids)) {
  524. auto field = import_ir_.insts().GetAs<SemIR::StructTypeField>(field_id);
  525. auto name_id = GetLocalNameId(field.name_id);
  526. auto field_type_id = context_.GetTypeIdForTypeConstant(field_const_id);
  527. fields.push_back(context_.AddInstInNoBlock(
  528. {Parse::NodeId::Invalid,
  529. SemIR::StructTypeField{.name_id = name_id,
  530. .field_type_id = field_type_id}}));
  531. }
  532. return context_.types().GetConstantId(
  533. context_.GetStructType(context_.inst_blocks().Add(fields)));
  534. }
  535. auto TryResolveTypedInst(SemIR::TupleType inst) -> SemIR::ConstantId {
  536. CARBON_CHECK(inst.type_id == SemIR::TypeId::TypeType);
  537. // Collect all constants first, locating unresolved ones in a single pass.
  538. auto initial_work = work_stack_.size();
  539. auto orig_elem_type_ids = import_ir_.type_blocks().Get(inst.elements_id);
  540. llvm::SmallVector<SemIR::ConstantId> elem_const_ids;
  541. elem_const_ids.reserve(orig_elem_type_ids.size());
  542. for (auto elem_type_id : orig_elem_type_ids) {
  543. elem_const_ids.push_back(GetLocalConstantId(elem_type_id));
  544. }
  545. if (HasNewWork(initial_work)) {
  546. return SemIR::ConstantId::Invalid;
  547. }
  548. // Prepare a vector of the tuple types for GetTupleType.
  549. llvm::SmallVector<SemIR::TypeId> elem_type_ids;
  550. elem_type_ids.reserve(orig_elem_type_ids.size());
  551. for (auto elem_const_id : elem_const_ids) {
  552. elem_type_ids.push_back(context_.GetTypeIdForTypeConstant(elem_const_id));
  553. }
  554. return context_.types().GetConstantId(context_.GetTupleType(elem_type_ids));
  555. }
  556. auto TryResolveTypedInst(SemIR::UnboundElementType inst)
  557. -> SemIR::ConstantId {
  558. auto initial_work = work_stack_.size();
  559. CARBON_CHECK(inst.type_id == SemIR::TypeId::TypeType);
  560. auto class_const_id = GetLocalConstantId(inst.class_type_id);
  561. auto elem_const_id = GetLocalConstantId(inst.element_type_id);
  562. if (HasNewWork(initial_work)) {
  563. return SemIR::ConstantId::Invalid;
  564. }
  565. return context_.types().GetConstantId(context_.GetUnboundElementType(
  566. context_.GetTypeIdForTypeConstant(class_const_id),
  567. context_.GetTypeIdForTypeConstant(elem_const_id)));
  568. }
  569. Context& context_;
  570. SemIR::ImportIRId import_ir_id_;
  571. const SemIR::File& import_ir_;
  572. SemIR::ConstantValueStore& import_ir_constant_values_;
  573. llvm::SmallVector<Work> work_stack_;
  574. };
  575. auto TryResolveImportRefUnused(Context& context, SemIR::InstId inst_id)
  576. -> void {
  577. auto inst = context.insts().Get(inst_id);
  578. auto import_ref = inst.TryAs<SemIR::ImportRefUnused>();
  579. if (!import_ref) {
  580. return;
  581. }
  582. const SemIR::File& import_ir = *context.import_irs().Get(import_ref->ir_id);
  583. auto import_inst = import_ir.insts().Get(import_ref->inst_id);
  584. ImportRefResolver resolver(context, import_ref->ir_id);
  585. auto type_id = resolver.ResolveType(import_inst.type_id());
  586. auto constant_id = resolver.Resolve(import_ref->inst_id);
  587. // TODO: Once ClassDecl/InterfaceDecl are supported (no longer return Error),
  588. // remove this.
  589. if (constant_id == SemIR::ConstantId::Error) {
  590. type_id = SemIR::TypeId::Error;
  591. }
  592. // Replace the ImportRefUnused instruction with an ImportRefUsed. This doesn't
  593. // use ReplaceInstBeforeConstantUse because it would trigger TryEvalInst, and
  594. // we're instead doing constant evaluation here in order to minimize recursion
  595. // risks.
  596. context.sem_ir().insts().Set(
  597. inst_id,
  598. SemIR::ImportRefUsed{type_id, import_ref->ir_id, import_ref->inst_id});
  599. // Store the constant for both the ImportRefUsed and imported instruction.
  600. context.constant_values().Set(inst_id, constant_id);
  601. }
  602. } // namespace Carbon::Check