generic.cpp 5.4 KB

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