node_stack.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef CARBON_TOOLCHAIN_CHECK_NODE_STACK_H_
  5. #define CARBON_TOOLCHAIN_CHECK_NODE_STACK_H_
  6. #include "common/vlog.h"
  7. #include "llvm/ADT/SmallVector.h"
  8. #include "toolchain/parse/node_ids.h"
  9. #include "toolchain/parse/node_kind.h"
  10. #include "toolchain/parse/tree.h"
  11. #include "toolchain/parse/typed_nodes.h"
  12. #include "toolchain/sem_ir/formatter.h"
  13. #include "toolchain/sem_ir/id_kind.h"
  14. #include "toolchain/sem_ir/ids.h"
  15. namespace Carbon::Check {
  16. // A non-discriminated union of ID types.
  17. class IdUnion {
  18. public:
  19. // The default constructor forms an invalid ID.
  20. explicit constexpr IdUnion() : index(IdBase::InvalidIndex) {}
  21. template <typename IdT>
  22. requires SemIR::IdKind::Contains<IdT>
  23. explicit constexpr IdUnion(IdT id) : index(id.index) {}
  24. using Kind = SemIR::IdKind::RawEnumType;
  25. // Returns the ID given its type.
  26. template <typename IdT>
  27. requires SemIR::IdKind::Contains<IdT>
  28. constexpr auto As() const -> IdT {
  29. return IdT(index);
  30. }
  31. // Returns the ID given its kind.
  32. template <SemIR::IdKind::RawEnumType K>
  33. constexpr auto As() const -> SemIR::IdKind::TypeFor<K> {
  34. return As<SemIR::IdKind::TypeFor<K>>();
  35. }
  36. // Translates an ID type to the enum ID kind. Returns Invalid if `IdT` isn't
  37. // a type that can be stored in this union.
  38. template <typename IdT>
  39. static constexpr auto KindFor() -> Kind {
  40. return SemIR::IdKind::For<IdT>;
  41. }
  42. private:
  43. decltype(IdBase::index) index;
  44. };
  45. // The stack of parse nodes representing the current state of a Check::Context.
  46. // Each parse node can have an associated id of some kind (instruction,
  47. // instruction block, function, class, ...).
  48. //
  49. // All pushes and pops will be vlogged.
  50. //
  51. // Pop APIs will run basic verification:
  52. //
  53. // - If receiving a Parse::NodeKind, verify that the node_id being popped has
  54. // that kind. Similarly, if receiving a Parse::NodeCategory, make sure the
  55. // of the popped node_id overlaps that category.
  56. // - Validates the kind of id data in the node based on the kind or category of
  57. // the node_id.
  58. //
  59. // These should be assumed API constraints unless otherwise mentioned on a
  60. // method. The main exception is PopAndIgnore, which doesn't do verification.
  61. class NodeStack {
  62. public:
  63. explicit NodeStack(const Parse::Tree& parse_tree,
  64. llvm::raw_ostream* vlog_stream)
  65. : parse_tree_(&parse_tree), vlog_stream_(vlog_stream) {}
  66. // Pushes a solo parse tree node onto the stack. Used when there is no
  67. // IR generated by the node.
  68. auto Push(Parse::NodeId node_id) -> void {
  69. auto kind = parse_tree_->node_kind(node_id);
  70. CARBON_CHECK(NodeKindToIdKind(kind) == Id::Kind::None)
  71. << "Parse kind expects an Id: " << kind;
  72. CARBON_VLOG() << "Node Push " << stack_.size() << ": " << kind
  73. << " -> <none>\n";
  74. CARBON_CHECK(stack_.size() < (1 << 20))
  75. << "Excessive stack size: likely infinite loop";
  76. stack_.push_back({.node_id = node_id, .id = Id()});
  77. }
  78. // Pushes a parse tree node onto the stack with an ID.
  79. template <typename IdT>
  80. auto Push(Parse::NodeId node_id, IdT id) -> void {
  81. auto kind = parse_tree_->node_kind(node_id);
  82. CARBON_CHECK(NodeKindToIdKind(kind) == Id::KindFor<IdT>())
  83. << "Parse kind expected a different IdT: " << kind << " -> " << id
  84. << "\n";
  85. CARBON_CHECK(id.is_valid())
  86. << "Push called with invalid id: " << parse_tree_->node_kind(node_id);
  87. CARBON_VLOG() << "Node Push " << stack_.size() << ": " << kind << " -> "
  88. << id << "\n";
  89. CARBON_CHECK(stack_.size() < (1 << 20))
  90. << "Excessive stack size: likely infinite loop";
  91. stack_.push_back({.node_id = node_id, .id = Id(id)});
  92. }
  93. // Returns whether there is a node of the specified kind on top of the stack.
  94. auto PeekIs(Parse::NodeKind kind) const -> bool {
  95. return !stack_.empty() && PeekNodeKind() == kind;
  96. }
  97. // Returns whether there is a node of the specified kind on top of the stack.
  98. // Templated for consistency with other functions taking a parse node kind.
  99. template <const Parse::NodeKind& RequiredParseKind>
  100. auto PeekIs() const -> bool {
  101. return PeekIs(RequiredParseKind);
  102. }
  103. // Returns whether the node on the top of the stack has an overlapping
  104. // category.
  105. auto PeekIs(Parse::NodeCategory category) const -> bool {
  106. return !stack_.empty() && PeekNodeKind().category().HasAnyOf(category);
  107. }
  108. // Returns whether the node on the top of the stack has an overlapping
  109. // category. Templated for consistency with other functions taking a parse
  110. // node category.
  111. template <Parse::NodeCategory::RawEnumType RequiredParseCategory>
  112. auto PeekIs() const -> bool {
  113. return PeekIs(RequiredParseCategory);
  114. }
  115. // Returns whether there is a node with the corresponding ID on top of the
  116. // stack.
  117. template <typename IdT>
  118. auto PeekIs() const -> bool {
  119. return !stack_.empty() &&
  120. NodeKindToIdKind(PeekNodeKind()) == Id::KindFor<IdT>();
  121. }
  122. // Returns whether the *next* node on the stack is a given kind. This doesn't
  123. // have the breadth of support versus other Peek functions because it's
  124. // expected to be used in narrow circumstances when determining how to treat
  125. // the *current* top of the stack.
  126. template <const Parse::NodeKind& RequiredParseKind>
  127. auto PeekNextIs() const -> bool {
  128. CARBON_CHECK(stack_.size() >= 2);
  129. return parse_tree_->node_kind(stack_[stack_.size() - 2].node_id) ==
  130. RequiredParseKind;
  131. }
  132. // Pops the top of the stack without any verification.
  133. auto PopAndIgnore() -> void {
  134. Entry back = stack_.pop_back_val();
  135. CARBON_VLOG() << "Node Pop " << stack_.size() << ": "
  136. << parse_tree_->node_kind(back.node_id) << " -> <ignored>\n";
  137. }
  138. // Pops the top of the stack and returns the node_id.
  139. template <const Parse::NodeKind& RequiredParseKind>
  140. auto PopForSoloNodeId() -> Parse::NodeIdForKind<RequiredParseKind> {
  141. Entry back = PopEntry<SemIR::InstId>();
  142. RequireIdKind(RequiredParseKind, Id::Kind::None);
  143. RequireParseKind<RequiredParseKind>(back.node_id);
  144. return Parse::NodeIdForKind<RequiredParseKind>(back.node_id);
  145. }
  146. // Pops the top of the stack if it is the given kind, and returns the
  147. // node_id. Otherwise, returns std::nullopt.
  148. template <const Parse::NodeKind& RequiredParseKind>
  149. auto PopForSoloNodeIdIf()
  150. -> std::optional<Parse::NodeIdForKind<RequiredParseKind>> {
  151. if (PeekIs<RequiredParseKind>()) {
  152. return PopForSoloNodeId<RequiredParseKind>();
  153. }
  154. return std::nullopt;
  155. }
  156. // Pops the top of the stack.
  157. template <const Parse::NodeKind& RequiredParseKind>
  158. auto PopAndDiscardSoloNodeId() -> void {
  159. PopForSoloNodeId<RequiredParseKind>();
  160. }
  161. // Pops the top of the stack if it is the given kind. Returns `true` if a node
  162. // was popped.
  163. template <const Parse::NodeKind& RequiredParseKind>
  164. auto PopAndDiscardSoloNodeIdIf() -> bool {
  165. if (!PeekIs<RequiredParseKind>()) {
  166. return false;
  167. }
  168. PopForSoloNodeId<RequiredParseKind>();
  169. return true;
  170. }
  171. // Pops an expression from the top of the stack and returns the node_id and
  172. // the ID.
  173. auto PopExprWithNodeId() -> std::pair<Parse::AnyExprId, SemIR::InstId>;
  174. // Pops a pattern from the top of the stack and returns the node_id and
  175. // the ID.
  176. auto PopPatternWithNodeId() -> std::pair<Parse::NodeId, SemIR::InstId> {
  177. return PopWithNodeId<SemIR::InstId>();
  178. }
  179. // Pops a name from the top of the stack and returns the node_id and
  180. // the ID.
  181. auto PopNameWithNodeId() -> std::pair<Parse::NodeId, SemIR::NameId> {
  182. return PopWithNodeId<SemIR::NameId>();
  183. }
  184. // Pops the top of the stack and returns the node_id and the ID.
  185. template <const Parse::NodeKind& RequiredParseKind>
  186. auto PopWithNodeId() -> auto {
  187. auto id = Peek<RequiredParseKind>();
  188. Parse::NodeIdForKind<RequiredParseKind> node_id(
  189. stack_.pop_back_val().node_id);
  190. return std::make_pair(node_id, id);
  191. }
  192. // Pops the top of the stack and returns the node_id and the ID.
  193. template <Parse::NodeCategory::RawEnumType RequiredParseCategory>
  194. auto PopWithNodeId() -> auto {
  195. auto id = Peek<RequiredParseCategory>();
  196. Parse::NodeIdInCategory<RequiredParseCategory> node_id(
  197. stack_.pop_back_val().node_id);
  198. return std::make_pair(node_id, id);
  199. }
  200. // Pops an expression from the top of the stack and returns the ID.
  201. // Expressions always map Parse::NodeCategory::Expr nodes to SemIR::InstId.
  202. auto PopExpr() -> SemIR::InstId { return PopExprWithNodeId().second; }
  203. // Pops a pattern from the top of the stack and returns the ID.
  204. // Patterns map multiple Parse::NodeKinds to SemIR::InstId always.
  205. auto PopPattern() -> SemIR::InstId { return PopPatternWithNodeId().second; }
  206. // Pops a name from the top of the stack and returns the ID.
  207. auto PopName() -> SemIR::NameId { return PopNameWithNodeId().second; }
  208. // Pops the top of the stack and returns the ID.
  209. template <const Parse::NodeKind& RequiredParseKind>
  210. auto Pop() -> auto {
  211. return PopWithNodeId<RequiredParseKind>().second;
  212. }
  213. // Pops the top of the stack and returns the ID.
  214. template <Parse::NodeCategory::RawEnumType RequiredParseCategory>
  215. auto Pop() -> auto {
  216. return PopWithNodeId<RequiredParseCategory>().second;
  217. }
  218. // Pops the top of the stack and returns the ID.
  219. template <typename IdT>
  220. auto Pop() -> IdT {
  221. return PopWithNodeId<IdT>().second;
  222. }
  223. // Pops the top of the stack if it has the given kind, and returns the ID.
  224. // Otherwise returns std::nullopt.
  225. template <const Parse::NodeKind& RequiredParseKind>
  226. auto PopIf() -> std::optional<decltype(Pop<RequiredParseKind>())> {
  227. if (PeekIs<RequiredParseKind>()) {
  228. return Pop<RequiredParseKind>();
  229. }
  230. return std::nullopt;
  231. }
  232. // Pops the top of the stack if it has the given category, and returns the ID.
  233. // Otherwise returns std::nullopt.
  234. template <Parse::NodeCategory::RawEnumType RequiredParseCategory>
  235. auto PopIf() -> std::optional<decltype(Pop<RequiredParseCategory>())> {
  236. if (PeekIs<RequiredParseCategory>()) {
  237. return Pop<RequiredParseCategory>();
  238. }
  239. return std::nullopt;
  240. }
  241. // Pops the top of the stack if it has the given category, and returns the ID.
  242. // Otherwise returns std::nullopt.
  243. template <typename IdT>
  244. auto PopIf() -> std::optional<IdT> {
  245. if (PeekIs<IdT>()) {
  246. return Pop<IdT>();
  247. }
  248. return std::nullopt;
  249. }
  250. // Pops the top of the stack and returns the node_id and the ID if it is
  251. // of the specified kind.
  252. template <const Parse::NodeKind& RequiredParseKind>
  253. auto PopWithNodeIdIf() -> std::pair<Parse::NodeIdForKind<RequiredParseKind>,
  254. decltype(PopIf<RequiredParseKind>())> {
  255. if (!PeekIs<RequiredParseKind>()) {
  256. return {Parse::NodeId::Invalid, std::nullopt};
  257. }
  258. return PopWithNodeId<RequiredParseKind>();
  259. }
  260. // Pops the top of the stack and returns the node_id and the ID if it is
  261. // of the specified category.
  262. template <Parse::NodeCategory::RawEnumType RequiredParseCategory>
  263. auto PopWithNodeIdIf()
  264. -> std::pair<Parse::NodeIdInCategory<RequiredParseCategory>,
  265. decltype(PopIf<RequiredParseCategory>())> {
  266. if (!PeekIs<RequiredParseCategory>()) {
  267. return {Parse::NodeId::Invalid, std::nullopt};
  268. }
  269. return PopWithNodeId<RequiredParseCategory>();
  270. }
  271. // Peeks at the parse node of the top of the node stack.
  272. auto PeekNodeId() const -> Parse::NodeId { return stack_.back().node_id; }
  273. // Peeks at the kind of the parse node of the top of the node stack.
  274. auto PeekNodeKind() const -> Parse::NodeKind {
  275. return parse_tree_->node_kind(PeekNodeId());
  276. }
  277. // Peeks at the ID associated with the top of the name stack.
  278. template <const Parse::NodeKind& RequiredParseKind>
  279. auto Peek() const -> auto {
  280. Entry back = stack_.back();
  281. RequireParseKind<RequiredParseKind>(back.node_id);
  282. constexpr Id::Kind RequiredIdKind = NodeKindToIdKind(RequiredParseKind);
  283. return Peek<RequiredIdKind>();
  284. }
  285. // Peeks at the ID associated with the top of the name stack.
  286. template <Parse::NodeCategory::RawEnumType RequiredParseCategory>
  287. auto Peek() const -> auto {
  288. Entry back = stack_.back();
  289. RequireParseCategory<RequiredParseCategory>(back.node_id);
  290. constexpr std::optional<Id::Kind> RequiredIdKind =
  291. NodeCategoryToIdKind(RequiredParseCategory, false);
  292. static_assert(RequiredIdKind.has_value());
  293. return Peek<*RequiredIdKind>();
  294. }
  295. // Prints the stack for a stack dump.
  296. auto PrintForStackDump(SemIR::Formatter& formatter, int indent,
  297. llvm::raw_ostream& output) const -> void;
  298. auto empty() const -> bool { return stack_.empty(); }
  299. auto size() const -> size_t { return stack_.size(); }
  300. protected:
  301. // An ID that can be associated with a parse node.
  302. //
  303. // Each parse node kind has a corresponding Id::Kind indicating which kind of
  304. // ID is stored, computed by NodeKindToIdKind. Id::Kind::None indicates
  305. // that the parse node has no associated ID, in which case the *SoloNodeId
  306. // functions should be used to push and pop it. Id::Kind::Invalid indicates
  307. // that the parse node should not appear in the node stack at all.
  308. using Id = IdUnion;
  309. // An entry in stack_.
  310. struct Entry {
  311. // The parse node associated with the stack entry.
  312. Parse::NodeId node_id;
  313. // The ID associated with this parse node. The kind of ID is determined by
  314. // the kind of the parse node, so a separate discriminiator is not needed.
  315. Id id;
  316. };
  317. static_assert(sizeof(Entry) == 8, "Unexpected Entry size");
  318. // Translate a parse node category to the enum ID kind it should always
  319. // provide, if it is consistent.
  320. static constexpr auto NodeCategoryToIdKind(Parse::NodeCategory category,
  321. bool for_node_kind)
  322. -> std::optional<Id::Kind> {
  323. std::optional<Id::Kind> result;
  324. auto set_id_if_category_is = [&](Parse::NodeCategory cat, Id::Kind kind) {
  325. if (category.HasAnyOf(cat)) {
  326. // Check for no consistent Id::Kind due to category with multiple bits
  327. // set. When computing the Id::Kind for a node kind, a partial category
  328. // match is OK, so long as we don't match two inconsistent categories.
  329. // When computing the Id::Kind for a category query, the query can't
  330. // have any extra bits set or we could be popping a node that is not in
  331. // this category.
  332. if (for_node_kind ? result.has_value() : category.HasAnyOf(~cat)) {
  333. result = Id::Kind::Invalid;
  334. } else {
  335. result = kind;
  336. }
  337. }
  338. };
  339. // TODO: Patterns should also produce an `InstId`, but currently
  340. // `TuplePattern` produces an `InstBlockId`.
  341. set_id_if_category_is(Parse::NodeCategory::Expr,
  342. Id::KindFor<SemIR::InstId>());
  343. set_id_if_category_is(Parse::NodeCategory::MemberName,
  344. Id::KindFor<SemIR::NameId>());
  345. set_id_if_category_is(Parse::NodeCategory::ImplAs,
  346. Id::KindFor<SemIR::TypeId>());
  347. set_id_if_category_is(Parse::NodeCategory::Decl |
  348. Parse::NodeCategory::Statement |
  349. Parse::NodeCategory::Modifier,
  350. Id::Kind::None);
  351. return result;
  352. }
  353. using IdKindTableType = std::array<Id::Kind, Parse::NodeKind::ValidCount>;
  354. // Lookup table to implement `NodeKindToIdKind`. Initialized to the
  355. // return value of `ComputeIdKindTable()`.
  356. static const IdKindTableType IdKindTable;
  357. static constexpr auto ComputeIdKindTable() -> IdKindTableType {
  358. IdKindTableType table = {};
  359. auto to_id_kind =
  360. [](const Parse::NodeKind::Definition& node_kind) -> Id::Kind {
  361. if (auto from_category =
  362. NodeCategoryToIdKind(node_kind.category(), true)) {
  363. return *from_category;
  364. }
  365. switch (node_kind) {
  366. case Parse::NodeKind::Addr:
  367. case Parse::NodeKind::BindingPattern:
  368. case Parse::NodeKind::CallExprStart:
  369. case Parse::NodeKind::CompileTimeBindingPattern:
  370. case Parse::NodeKind::IfExprThen:
  371. case Parse::NodeKind::ReturnType:
  372. case Parse::NodeKind::ShortCircuitOperandAnd:
  373. case Parse::NodeKind::ShortCircuitOperandOr:
  374. case Parse::NodeKind::StructField:
  375. case Parse::NodeKind::StructTypeField:
  376. return Id::KindFor<SemIR::InstId>();
  377. case Parse::NodeKind::IfCondition:
  378. case Parse::NodeKind::IfExprIf:
  379. case Parse::NodeKind::ImplForall:
  380. case Parse::NodeKind::ImplicitParamList:
  381. case Parse::NodeKind::TuplePattern:
  382. case Parse::NodeKind::WhileCondition:
  383. case Parse::NodeKind::WhileConditionStart:
  384. return Id::KindFor<SemIR::InstBlockId>();
  385. case Parse::NodeKind::FunctionDefinitionStart:
  386. case Parse::NodeKind::BuiltinFunctionDefinitionStart:
  387. return Id::KindFor<SemIR::FunctionId>();
  388. case Parse::NodeKind::ClassDefinitionStart:
  389. return Id::KindFor<SemIR::ClassId>();
  390. case Parse::NodeKind::InterfaceDefinitionStart:
  391. return Id::KindFor<SemIR::InterfaceId>();
  392. case Parse::NodeKind::ImplDefinitionStart:
  393. return Id::KindFor<SemIR::ImplId>();
  394. case Parse::NodeKind::SelfValueName:
  395. return Id::KindFor<SemIR::NameId>();
  396. case Parse::NodeKind::DefaultLibrary:
  397. case Parse::NodeKind::LibraryName:
  398. return Id::KindFor<SemIR::LibraryNameId>();
  399. case Parse::NodeKind::ArrayExprSemi:
  400. case Parse::NodeKind::BuiltinName:
  401. case Parse::NodeKind::ClassIntroducer:
  402. case Parse::NodeKind::CodeBlockStart:
  403. case Parse::NodeKind::FunctionIntroducer:
  404. case Parse::NodeKind::IfStatementElse:
  405. case Parse::NodeKind::ImplicitParamListStart:
  406. case Parse::NodeKind::ImplIntroducer:
  407. case Parse::NodeKind::InterfaceIntroducer:
  408. case Parse::NodeKind::LetInitializer:
  409. case Parse::NodeKind::LetIntroducer:
  410. case Parse::NodeKind::ReturnedModifier:
  411. case Parse::NodeKind::ReturnStatementStart:
  412. case Parse::NodeKind::ReturnVarModifier:
  413. case Parse::NodeKind::StructLiteralStart:
  414. case Parse::NodeKind::StructTypeLiteralStart:
  415. case Parse::NodeKind::TupleLiteralStart:
  416. case Parse::NodeKind::TuplePatternStart:
  417. case Parse::NodeKind::VariableInitializer:
  418. case Parse::NodeKind::VariableIntroducer:
  419. return Id::Kind::None;
  420. default:
  421. return Id::Kind::Invalid;
  422. }
  423. };
  424. #define CARBON_PARSE_NODE_KIND(Name) \
  425. table[Parse::Name::Kind.AsInt()] = to_id_kind(Parse::Name::Kind);
  426. #include "toolchain/parse/node_kind.def"
  427. return table;
  428. }
  429. // Translate a parse node kind to the enum ID kind it should always provide.
  430. static constexpr auto NodeKindToIdKind(Parse::NodeKind kind) -> Id::Kind {
  431. return IdKindTable[kind.AsInt()];
  432. }
  433. // Peeks at the ID associated with the top of the name stack.
  434. template <Id::Kind RequiredIdKind>
  435. auto Peek() const -> auto {
  436. Id id = stack_.back().id;
  437. return id.As<RequiredIdKind>();
  438. }
  439. // Pops an entry.
  440. template <typename IdT>
  441. auto PopEntry() -> Entry {
  442. Entry back = stack_.pop_back_val();
  443. CARBON_VLOG() << "Node Pop " << stack_.size() << ": "
  444. << parse_tree_->node_kind(back.node_id) << " -> "
  445. << back.id.template As<IdT>() << "\n";
  446. return back;
  447. }
  448. // Pops the top of the stack and returns the node_id and the ID.
  449. template <typename IdT>
  450. auto PopWithNodeId() -> std::pair<Parse::NodeId, IdT> {
  451. Entry back = PopEntry<IdT>();
  452. RequireIdKind(parse_tree_->node_kind(back.node_id), Id::KindFor<IdT>());
  453. return {back.node_id, back.id.template As<IdT>()};
  454. }
  455. // Require a Parse::NodeKind be mapped to a particular Id::Kind.
  456. auto RequireIdKind(Parse::NodeKind parse_kind, Id::Kind id_kind) const
  457. -> void {
  458. CARBON_CHECK(NodeKindToIdKind(parse_kind) == id_kind)
  459. << "Unexpected Id::Kind mapping for " << parse_kind << ": expected "
  460. << static_cast<int>(id_kind) << ", found "
  461. << static_cast<int>(NodeKindToIdKind(parse_kind));
  462. }
  463. // Require an entry to have the given Parse::NodeKind.
  464. template <const Parse::NodeKind& RequiredParseKind>
  465. auto RequireParseKind(Parse::NodeId node_id) const -> void {
  466. auto actual_kind = parse_tree_->node_kind(node_id);
  467. CARBON_CHECK(RequiredParseKind == actual_kind)
  468. << "Expected " << RequiredParseKind << ", found " << actual_kind;
  469. }
  470. // Require an entry to have the given Parse::NodeCategory.
  471. template <Parse::NodeCategory::RawEnumType RequiredParseCategory>
  472. auto RequireParseCategory(Parse::NodeId node_id) const -> void {
  473. auto kind = parse_tree_->node_kind(node_id);
  474. CARBON_CHECK(kind.category().HasAnyOf(RequiredParseCategory))
  475. << "Expected " << RequiredParseCategory << ", found " << kind
  476. << " with category " << kind.category();
  477. }
  478. // The file's parse tree.
  479. const Parse::Tree* parse_tree_;
  480. // Whether to print verbose output.
  481. llvm::raw_ostream* vlog_stream_;
  482. // The actual stack.
  483. // PushEntry and PopEntry control modification in order to centralize
  484. // vlogging.
  485. llvm::SmallVector<Entry> stack_;
  486. };
  487. constexpr NodeStack::IdKindTableType NodeStack::IdKindTable =
  488. ComputeIdKindTable();
  489. inline auto NodeStack::PopExprWithNodeId()
  490. -> std::pair<Parse::AnyExprId, SemIR::InstId> {
  491. return PopWithNodeId<Parse::NodeCategory::Expr>();
  492. }
  493. } // namespace Carbon::Check
  494. #endif // CARBON_TOOLCHAIN_CHECK_NODE_STACK_H_