generic.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  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. namespace Carbon::SemIR {
  7. class SpecificStore::KeyContext : public TranslatingKeyContext<KeyContext> {
  8. public:
  9. // A lookup key for a specific.
  10. struct Key {
  11. GenericId generic_id;
  12. InstBlockId args_id;
  13. friend auto operator==(const Key&, const Key&) -> bool = default;
  14. };
  15. explicit KeyContext(llvm::ArrayRef<Specific> specifics)
  16. : specifics_(specifics) {}
  17. auto TranslateKey(SpecificId id) const -> Key {
  18. const auto& specific = specifics_[id.index];
  19. return {.generic_id = specific.generic_id, .args_id = specific.args_id};
  20. }
  21. private:
  22. llvm::ArrayRef<Specific> specifics_;
  23. };
  24. auto SpecificStore::GetOrAdd(GenericId generic_id, InstBlockId args_id)
  25. -> SpecificId {
  26. CARBON_CHECK(generic_id.is_valid());
  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_.array_ref()))
  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.Add(MemUsage::ConcatLabel(label, "lookup_table_"), lookup_table_,
  41. KeyContext(specifics_.array_ref()));
  42. }
  43. auto GetConstantInSpecific(const File& sem_ir, SpecificId specific_id,
  44. ConstantId const_id) -> ConstantId {
  45. if (!const_id.is_symbolic()) {
  46. // Type does not depend on a generic parameter.
  47. return const_id;
  48. }
  49. const auto& symbolic = sem_ir.constant_values().GetSymbolicConstant(const_id);
  50. if (!symbolic.generic_id.is_valid()) {
  51. // Constant is an abstract symbolic constant, not associated with some
  52. // particular generic.
  53. return const_id;
  54. }
  55. if (!specific_id.is_valid()) {
  56. // TODO: We have a generic constant but no specific. Investigate whether we
  57. // can CHECK-fail here. For now, produce the canonical value of the
  58. // constant.
  59. return sem_ir.constant_values().Get(symbolic.inst_id);
  60. }
  61. const auto& specific = sem_ir.specifics().Get(specific_id);
  62. if (specific.generic_id != symbolic.generic_id) {
  63. // TODO: Given an specific for the wrong generic. If the symbolic constant
  64. // is from an enclosing generic, take the value from the corresponding
  65. // specific. Otherwise, CHECK-fail.
  66. return sem_ir.constant_values().Get(symbolic.inst_id);
  67. }
  68. auto value_block_id = specific.GetValueBlock(symbolic.index.region());
  69. CARBON_CHECK(value_block_id.is_valid())
  70. << "Queried region of " << specific_id << " before it was resolved.";
  71. return sem_ir.constant_values().Get(
  72. sem_ir.inst_blocks().Get(value_block_id)[symbolic.index.index()]);
  73. }
  74. auto GetConstantValueInSpecific(const File& sem_ir, SpecificId specific_id,
  75. InstId inst_id) -> ConstantId {
  76. return GetConstantInSpecific(sem_ir, specific_id,
  77. sem_ir.constant_values().Get(inst_id));
  78. }
  79. auto GetTypeInSpecific(const File& sem_ir, SpecificId specific_id,
  80. TypeId type_id) -> TypeId {
  81. return TypeId::ForTypeConstant(GetConstantInSpecific(
  82. sem_ir, specific_id, sem_ir.types().GetConstantId(type_id)));
  83. }
  84. } // namespace Carbon::SemIR