lexical_lookup.h 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  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_LEXICAL_LOOKUP_H_
  5. #define CARBON_TOOLCHAIN_CHECK_LEXICAL_LOOKUP_H_
  6. #include "toolchain/check/scope_index.h"
  7. #include "toolchain/sem_ir/ids.h"
  8. namespace Carbon::Check {
  9. // Manages lexical lookup information for NameIds.
  10. //
  11. // Values are a stack of name lookup results in the ancestor scopes. This offers
  12. // constant-time lookup of names, regardless of how many scopes exist between
  13. // the name declaration and reference. The corresponding scope for each lookup
  14. // result is tracked, so that lexical lookup results can be interleaved with
  15. // lookup results from non-lexical scopes such as classes.
  16. class LexicalLookup {
  17. public:
  18. // A lookup result.
  19. struct Result {
  20. // The instruction that was added to lookup.
  21. SemIR::InstId inst_id;
  22. // The scope in which the instruction was added.
  23. ScopeIndex scope_index;
  24. };
  25. // A lookup result that has been temporarily removed from scope.
  26. struct SuspendedResult {
  27. // The lookup index. This is notionally a size_t, but is stored in 32 bits
  28. // to keep this type small, which helps to keep SuspendedFunctions small.
  29. uint32_t index;
  30. // The lookup result.
  31. SemIR::InstId inst_id;
  32. };
  33. explicit LexicalLookup(const CanonicalValueStore<IdentifierId>& identifiers)
  34. : lookup_(identifiers.size() + SemIR::NameId::NonIndexValueCount) {}
  35. // Returns the lexical lookup results for a name.
  36. auto Get(SemIR::NameId name_id) -> llvm::SmallVector<Result, 2>& {
  37. auto index = GetLookupIndex(name_id);
  38. CARBON_CHECK(
  39. index < lookup_.size(),
  40. "An identifier was added after the Context was initialized. Currently, "
  41. "we expect that new identifiers will never be used with lexical lookup "
  42. "(they're added for things like detecting name collisions in imports). "
  43. "That might change with metaprogramming: if it does, we may need to "
  44. "start resizing `lookup_`, either on each identifier addition or in "
  45. "Get` where this CHECK currently fires.");
  46. return lookup_[index];
  47. }
  48. // Temporarily remove the top lookup result for `name_id` from scope.
  49. auto Suspend(SemIR::NameId name_id) -> SuspendedResult {
  50. auto index = GetLookupIndex(name_id);
  51. auto& results = lookup_[index];
  52. CARBON_CHECK(!results.empty(), "Suspending a nonexistent result for {0}.",
  53. name_id);
  54. CARBON_CHECK(index <= std::numeric_limits<uint32_t>::max(),
  55. "Unexpectedly large index {0} for name ID", index);
  56. return {.index = static_cast<uint32_t>(index),
  57. .inst_id = results.pop_back_val().inst_id};
  58. }
  59. // Restore a previously-suspended lookup result.
  60. auto Restore(SuspendedResult sus, ScopeIndex index) -> void {
  61. lookup_[sus.index].push_back(
  62. {.inst_id = sus.inst_id, .scope_index = index});
  63. }
  64. private:
  65. // Get the index at which the specified name is stored in `lookup_`.
  66. auto GetLookupIndex(SemIR::NameId name_id) -> size_t {
  67. return static_cast<ssize_t>(name_id.index) +
  68. SemIR::NameId::NonIndexValueCount;
  69. }
  70. // Maps identifiers to name lookup results.
  71. // TODO: Consider TinyPtrVector<Result> or similar. For now, use a small size
  72. // of 2 to cover the common case.
  73. llvm::SmallVector<llvm::SmallVector<Result, 2>> lookup_;
  74. };
  75. } // namespace Carbon::Check
  76. #endif // CARBON_TOOLCHAIN_CHECK_LEXICAL_LOOKUP_H_