lexical_lookup.h 3.6 KB

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