impl.h 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  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_SEM_IR_IMPL_H_
  5. #define CARBON_TOOLCHAIN_SEM_IR_IMPL_H_
  6. #include "common/map.h"
  7. #include "toolchain/base/value_store.h"
  8. #include "toolchain/sem_ir/entity_with_params_base.h"
  9. #include "toolchain/sem_ir/facet_type_info.h"
  10. #include "toolchain/sem_ir/ids.h"
  11. namespace Carbon::SemIR {
  12. struct ImplFields {
  13. // This following members always have values and do not change.
  14. // The type for which the impl is implementing a constraint.
  15. TypeInstId self_id;
  16. // The constraint that the impl implements.
  17. TypeInstId constraint_id;
  18. // The single interface to implement from `constraint_id`.
  19. // The members are `None` if `constraint_id` isn't complete or doesn't
  20. // correspond to a single interface.
  21. SpecificInterface interface;
  22. // The witness for the impl. This can be `BuiltinErrorInst` or an import
  23. // reference. Note that the entries in the witness are updated at the end of
  24. // the impl definition.
  25. InstId witness_id = InstId::None;
  26. // The following members are set at the `{` of the impl definition.
  27. // The impl scope.
  28. NameScopeId scope_id = NameScopeId::None;
  29. // The first block of the impl body.
  30. // TODO: Handle control flow in the impl body, such as if-expressions.
  31. InstBlockId body_block_id = InstBlockId::None;
  32. // Whether the impl declaration is marked `final`.
  33. bool is_final;
  34. // The following members are set at the `}` of the impl definition.
  35. bool defined = false;
  36. };
  37. // An implementation of a constraint. See EntityWithParamsBase regarding the
  38. // inheritance here.
  39. struct Impl : public EntityWithParamsBase,
  40. public ImplFields,
  41. public Printable<Impl> {
  42. auto Print(llvm::raw_ostream& out) const -> void {
  43. out << "{self: " << self_id << ", constraint: " << constraint_id
  44. << ", witness: " << witness_id << "}";
  45. }
  46. // This is false until we reach the `}` of the impl definition.
  47. auto is_complete() const -> bool { return defined; }
  48. // Determines whether this impl's definition has begun but not yet ended.
  49. auto is_being_defined() const -> bool {
  50. return has_definition_started() && !is_complete();
  51. }
  52. };
  53. // A collection of `Impl`s, which can be accessed by the self type and
  54. // constraint implemented.
  55. class ImplStore {
  56. private:
  57. // An ID of either a single impl or a lookup bucket.
  58. class ImplOrLookupBucketId : public IdBase<ImplOrLookupBucketId> {
  59. public:
  60. static constexpr llvm::StringLiteral Label = "impl_or_lookup_bucket";
  61. // An ID with no value, corresponding to to ImplId::None.
  62. static const ImplOrLookupBucketId None;
  63. static auto ForImplId(ImplId impl_id) -> ImplOrLookupBucketId {
  64. return ImplOrLookupBucketId(impl_id.index);
  65. }
  66. static auto ForBucket(int bucket) -> ImplOrLookupBucketId {
  67. return ImplOrLookupBucketId(ImplId::NoneIndex - bucket - 1);
  68. }
  69. // Returns whether this ID represents a bucket index, rather than an ImplId.
  70. // `None` is not a bucket index.
  71. auto is_bucket() const { return index < ImplId::NoneIndex; }
  72. // Returns the bucket index represented by this ID. Requires is_bucket().
  73. auto bucket() const -> int {
  74. CARBON_CHECK(is_bucket());
  75. return ImplId::NoneIndex - index - 1;
  76. }
  77. // Returns the ImplId index represented by this ID. Requires !is_bucket().
  78. auto impl_id() const -> ImplId {
  79. CARBON_CHECK(!is_bucket());
  80. return ImplId(index);
  81. }
  82. private:
  83. explicit constexpr ImplOrLookupBucketId(int index) : IdBase(index) {}
  84. };
  85. public:
  86. // A reference to an impl lookup bucket. This represents a list of impls with
  87. // the same self and constraint type.
  88. //
  89. // The bucket is held indirectly as an `ImplOrLookupBucketId`, in one of three
  90. // states:
  91. //
  92. // - `ImplId::None` represents an empty bucket.
  93. // - An `ImplId` value represents a bucket with exactly one impl. This is
  94. // expected to be by far the most common case.
  95. // - A lookup bucket index represents an index within the `ImplStore`'s
  96. // array of variable-sized lookup buckets.
  97. class LookupBucketRef {
  98. public:
  99. LookupBucketRef(ImplStore& store, ImplOrLookupBucketId& id)
  100. : store_(&store), id_(&id), single_id_storage_(ImplId::None) {
  101. if (!id.is_bucket()) {
  102. single_id_storage_ = id.impl_id();
  103. }
  104. }
  105. auto begin() const -> const ImplId* {
  106. if (id_->is_bucket()) {
  107. return store_->lookup_buckets_[id_->bucket()].begin();
  108. }
  109. return &single_id_storage_;
  110. }
  111. auto end() const -> const ImplId* {
  112. if (id_->is_bucket()) {
  113. return store_->lookup_buckets_[id_->bucket()].end();
  114. }
  115. return &single_id_storage_ + (id_->has_value() ? 1 : 0);
  116. }
  117. // Adds an impl to this lookup bucket. Only impls from the current file and
  118. // its API file should be added in this way. Impls from other files do not
  119. // need to be found by impl redeclaration lookup so should not be added.
  120. auto push_back(ImplId impl_id) -> void {
  121. if (!id_->has_value()) {
  122. *id_ = ImplOrLookupBucketId::ForImplId(impl_id);
  123. single_id_storage_ = impl_id;
  124. } else if (!id_->is_bucket()) {
  125. auto first_id = id_->impl_id();
  126. *id_ = ImplOrLookupBucketId::ForBucket(store_->lookup_buckets_.size());
  127. store_->lookup_buckets_.push_back({first_id, impl_id});
  128. } else {
  129. store_->lookup_buckets_[id_->bucket()].push_back(impl_id);
  130. }
  131. }
  132. private:
  133. ImplStore* store_;
  134. ImplOrLookupBucketId* id_;
  135. // Storage for a single ImplId. Used to support iteration over the contents
  136. // of the bucket when it contains a single ImplId.
  137. ImplId single_id_storage_;
  138. };
  139. explicit ImplStore(File& sem_ir);
  140. // Returns a reference to the lookup bucket containing the list of impls with
  141. // this self type and constraint, or adds a new bucket if this is the first
  142. // time we've seen an impl of this kind. The lookup bucket reference remains
  143. // valid until this function is called again.
  144. auto GetOrAddLookupBucket(const Impl& impl) -> LookupBucketRef;
  145. // Adds the specified impl to the store. Does not add it to impl lookup.
  146. auto Add(Impl impl) -> ImplId { return values_.Add(impl); }
  147. // Returns a mutable value for an ID.
  148. auto Get(ImplId id) -> Impl& { return values_.Get(id); }
  149. // Returns the value for an ID.
  150. auto Get(ImplId id) const -> const Impl& { return values_.Get(id); }
  151. auto OutputYaml() const -> Yaml::OutputMapping {
  152. return values_.OutputYaml();
  153. }
  154. auto GetRawIndex(ImplId id) const -> int32_t {
  155. return values_.GetRawIndex(id);
  156. }
  157. // Collects memory usage of members.
  158. auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
  159. -> void {
  160. mem_usage.Collect(MemUsage::ConcatLabel(label, "values_"), values_);
  161. mem_usage.Collect(MemUsage::ConcatLabel(label, "lookup_"), lookup_);
  162. }
  163. auto values() const [[clang::lifetimebound]]
  164. -> ValueStore<ImplId, Impl>::Range {
  165. return values_.values();
  166. }
  167. auto size() const -> size_t { return values_.size(); }
  168. auto enumerate() const [[clang::lifetimebound]] -> auto {
  169. return values_.enumerate();
  170. }
  171. private:
  172. File& sem_ir_;
  173. ValueStore<ImplId, Impl> values_;
  174. Map<std::tuple<InstId, InterfaceId, SpecificId>, ImplOrLookupBucketId>
  175. lookup_;
  176. // Buckets with at least 2 entries, which will be rare; see LookupBucketRef.
  177. llvm::SmallVector<llvm::SmallVector<ImplId, 2>> lookup_buckets_;
  178. };
  179. constexpr inline ImplStore::ImplOrLookupBucketId
  180. ImplStore::ImplOrLookupBucketId::None(NoneIndex);
  181. } // namespace Carbon::SemIR
  182. #endif // CARBON_TOOLCHAIN_SEM_IR_IMPL_H_