lexical_lookup.h 3.5 KB

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