generic.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  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. #include "toolchain/sem_ir/generic.h"
  5. #include "toolchain/sem_ir/file.h"
  6. #include "toolchain/sem_ir/typed_insts.h"
  7. namespace Carbon::SemIR {
  8. class SpecificStore::KeyContext : public TranslatingKeyContext<KeyContext> {
  9. public:
  10. // A lookup key for a specific.
  11. struct Key {
  12. GenericId generic_id;
  13. InstBlockId args_id;
  14. friend auto operator==(const Key&, const Key&) -> bool = default;
  15. };
  16. explicit KeyContext(const ValueStore<SpecificId>* specifics)
  17. : specifics_(specifics) {}
  18. auto TranslateKey(SpecificId id) const -> Key {
  19. const auto& specific = specifics_->Get(id);
  20. return {.generic_id = specific.generic_id, .args_id = specific.args_id};
  21. }
  22. private:
  23. const ValueStore<SpecificId>* specifics_;
  24. };
  25. auto SpecificStore::GetOrAdd(GenericId generic_id, InstBlockId args_id)
  26. -> SpecificId {
  27. CARBON_CHECK(generic_id.has_value());
  28. return lookup_table_
  29. .Insert(
  30. KeyContext::Key{.generic_id = generic_id, .args_id = args_id},
  31. [&] {
  32. return specifics_.Add(
  33. {.generic_id = generic_id, .args_id = args_id});
  34. },
  35. KeyContext(&specifics_))
  36. .key();
  37. }
  38. auto SpecificStore::CollectMemUsage(MemUsage& mem_usage,
  39. llvm::StringRef label) const -> void {
  40. mem_usage.Collect(MemUsage::ConcatLabel(label, "specifics_"), specifics_);
  41. mem_usage.Collect(MemUsage::ConcatLabel(label, "lookup_table_"),
  42. lookup_table_, KeyContext(&specifics_));
  43. }
  44. static auto GetConstantInSpecific(const File& specific_ir,
  45. SpecificId specific_id, const File& const_ir,
  46. ConstantId const_id)
  47. -> std::pair<const File*, ConstantId> {
  48. if (!const_id.is_symbolic()) {
  49. // The constant does not depend on a generic parameter.
  50. return {&const_ir, const_id};
  51. }
  52. const auto& symbolic =
  53. const_ir.constant_values().GetSymbolicConstant(const_id);
  54. if (!symbolic.generic_id.has_value()) {
  55. // The constant is an unattached symbolic constant, not associated with some
  56. // particular generic.
  57. return {&const_ir, const_id};
  58. }
  59. if (!specific_id.has_value()) {
  60. // We have a generic constant but no specific. We treat this as a request
  61. // for the value that should be used within the generic itself, which is the
  62. // unattached constant.
  63. return {&const_ir, const_ir.constant_values().Get(symbolic.inst_id)};
  64. }
  65. const auto& specific = specific_ir.specifics().Get(specific_id);
  66. // TODO: Enforce this check even if the generic and specific are in different
  67. // IRs.
  68. CARBON_CHECK(
  69. &specific_ir != &const_ir || specific.generic_id == symbolic.generic_id,
  70. "Given a specific for the wrong generic");
  71. auto value_block_id = specific.GetValueBlock(symbolic.index.region());
  72. if (!value_block_id.has_value()) {
  73. // For the self specific, we can see queries before the definition is
  74. // resolved. Return the unattached constant value.
  75. CARBON_CHECK(
  76. specific_ir.generics().GetSelfSpecific(
  77. specific_ir.specifics().Get(specific_id).generic_id) == specific_id,
  78. "Queried {0} in {1} for {2} before it was resolved.", symbolic.index,
  79. specific_id,
  80. specific_ir.insts().Get(
  81. specific_ir.generics().Get(specific.generic_id).decl_id));
  82. // TODO: Make sure this is the same value that we put in the self specific
  83. // when it's resolved. Consider not building value blocks for a self
  84. // specific.
  85. return {&const_ir, const_ir.constant_values().Get(symbolic.inst_id)};
  86. }
  87. return {&specific_ir,
  88. specific_ir.constant_values().Get(specific_ir.inst_blocks().Get(
  89. value_block_id)[symbolic.index.index()])};
  90. }
  91. auto GetConstantValueInSpecific(const File& sem_ir, SpecificId specific_id,
  92. InstId inst_id) -> ConstantId {
  93. return GetConstantInSpecific(sem_ir, specific_id, sem_ir,
  94. sem_ir.constant_values().GetAttached(inst_id))
  95. .second;
  96. }
  97. auto GetConstantValueInSpecific(const File& specific_ir, SpecificId specific_id,
  98. const File& inst_ir, InstId inst_id)
  99. -> std::pair<const File*, ConstantId> {
  100. return GetConstantInSpecific(specific_ir, specific_id, inst_ir,
  101. inst_ir.constant_values().GetAttached(inst_id));
  102. }
  103. auto GetTypeOfInstInSpecific(const File& sem_ir, SpecificId specific_id,
  104. InstId inst_id) -> TypeId {
  105. auto type_id = sem_ir.insts().GetAttachedType(inst_id);
  106. auto const_id = sem_ir.types().GetConstantId(type_id);
  107. auto [_, specific_const_id] =
  108. GetConstantInSpecific(sem_ir, specific_id, sem_ir, const_id);
  109. return TypeId::ForTypeConstant(specific_const_id);
  110. }
  111. auto GetTypeOfInstInSpecific(const File& specific_ir, SpecificId specific_id,
  112. const File& inst_ir, InstId inst_id)
  113. -> std::pair<const File*, TypeId> {
  114. auto type_id = inst_ir.insts().GetAttachedType(inst_id);
  115. auto const_id = inst_ir.types().GetConstantId(type_id);
  116. auto [result_ir, result_const_id] =
  117. GetConstantInSpecific(specific_ir, specific_id, inst_ir, const_id);
  118. return {result_ir, TypeId::ForTypeConstant(result_const_id)};
  119. }
  120. } // namespace Carbon::SemIR