full_pattern_stack.h 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  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_FULL_PATTERN_STACK_H_
  5. #define CARBON_TOOLCHAIN_CHECK_FULL_PATTERN_STACK_H_
  6. #include "common/array_stack.h"
  7. #include "common/check.h"
  8. #include "toolchain/check/lexical_lookup.h"
  9. #include "toolchain/sem_ir/ids.h"
  10. namespace Carbon::Check {
  11. // Stack of full-patterns currently being checked. When a pattern
  12. // is followed by an explicit initializer, name bindings should not be used
  13. // within that initializer, although they are usable before it (within the
  14. // pattern) and after it. This class keeps track of those state transitions.
  15. // It is structured as a stack to handle situations like a pattern that
  16. // contains an initializer, or a pattern in a lambda in an expression pattern.
  17. //
  18. // TODO: Unify this with Context::pattern_block_stack, or differentiate them
  19. // more clearly (and consider unifying this with ScopeStack instead).
  20. class FullPatternStack {
  21. public:
  22. explicit FullPatternStack(LexicalLookup* lookup) : lookup_(lookup) {}
  23. // Marks the possible start of a new full-pattern (i.e. a pattern which occurs
  24. // in a non-pattern context).
  25. auto PushFullPattern() -> void { bind_name_stack_.PushArray(); }
  26. // Marks the start of the initializer for the full-pattern at the top of the
  27. // stack.
  28. auto StartPatternInitializer() -> void {
  29. for (auto& [name_id, inst_id] : bind_name_stack_.PeekArray()) {
  30. CARBON_CHECK(inst_id == SemIR::InstId::InitTombstone);
  31. auto& lookup_result = lookup_->Get(name_id);
  32. if (!lookup_result.empty()) {
  33. // TODO: find a way to preserve location information, so that we can
  34. // provide good diagnostics for a redeclaration of `name_id` in
  35. // the initializer, if that becomes possible.
  36. std::swap(lookup_result.back().inst_id, inst_id);
  37. }
  38. }
  39. }
  40. // Marks the end of the initializer for the full-pattern at the top of the
  41. // stack.
  42. auto EndPatternInitializer() -> void {
  43. for (auto& [name_id, inst_id] : bind_name_stack_.PeekArray()) {
  44. auto& lookup_result = lookup_->Get(name_id);
  45. if (!lookup_result.empty()) {
  46. std::swap(lookup_result.back().inst_id, inst_id);
  47. }
  48. CARBON_CHECK(inst_id == SemIR::InstId::InitTombstone);
  49. }
  50. }
  51. // Marks the end of checking for the full-pattern at the top of the stack.
  52. // This cannot be called while processing an initializer for the top
  53. // pattern.
  54. auto PopFullPattern() -> void { bind_name_stack_.PopArray(); }
  55. // Records that `bind_inst_id` was introduced by the full-pattern at the
  56. // top of the stack.
  57. auto AddBindName(SemIR::NameId name_id) -> void {
  58. bind_name_stack_.AppendToTop(
  59. {.name_id = name_id, .inst_id = SemIR::InstId::InitTombstone});
  60. }
  61. private:
  62. LexicalLookup* lookup_;
  63. struct LookupEntry {
  64. SemIR::NameId name_id;
  65. SemIR::InstId inst_id;
  66. };
  67. ArrayStack<LookupEntry> bind_name_stack_;
  68. };
  69. } // namespace Carbon::Check
  70. #endif // CARBON_TOOLCHAIN_CHECK_FULL_PATTERN_STACK_H_