id_kind.h 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  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_ID_KIND_H_
  5. #define CARBON_TOOLCHAIN_SEM_IR_ID_KIND_H_
  6. #include <algorithm>
  7. #include "common/ostream.h"
  8. #include "toolchain/base/int.h"
  9. #include "toolchain/sem_ir/ids.h"
  10. namespace Carbon::SemIR {
  11. // An enum whose values are the specified types.
  12. template <typename... Types>
  13. class TypeEnum : public Printable<TypeEnum<Types...>> {
  14. public:
  15. using TypeTuple = std::tuple<Types...>;
  16. static constexpr size_t NumTypes = sizeof...(Types);
  17. static constexpr size_t NumValues = NumTypes + 2;
  18. static_assert(NumValues <= 256, "Too many types for raw enum.");
  19. // TODO: Works around a clang-format bug:
  20. // https://github.com/llvm/llvm-project/issues/85476
  21. #define CARBON_OPEN_ENUM [[clang::enum_extensibility(open)]]
  22. // The underlying raw enumeration type.
  23. //
  24. // The enum_extensibility attribute indicates that this enum is intended to
  25. // take values that do not correspond to its declared enumerators.
  26. enum class CARBON_OPEN_ENUM RawEnumType : uint8_t {
  27. // The first sizeof...(Types) values correspond to the types.
  28. // An explicitly invalid value.
  29. Invalid = NumTypes,
  30. // Indicates that no type should be used.
  31. // TODO: This doesn't really fit the model of this type, but it's convenient
  32. // for all of its users.
  33. None,
  34. };
  35. #undef CARBON_OPEN_ENUM
  36. // Accesses the type given an enum value.
  37. template <RawEnumType K>
  38. requires(K != RawEnumType::Invalid)
  39. using TypeFor = __type_pack_element<static_cast<size_t>(K), Types...>;
  40. // Workaround for Clang bug https://github.com/llvm/llvm-project/issues/85461
  41. template <RawEnumType Value>
  42. static constexpr auto FromRaw = TypeEnum(Value);
  43. // Names for the `Invalid` and `None` enumeration values.
  44. static constexpr const TypeEnum& Invalid = FromRaw<RawEnumType::Invalid>;
  45. static constexpr const TypeEnum& None = FromRaw<RawEnumType::None>;
  46. // Accesses the enumeration value for the type `IdT`. If `AllowInvalid` is
  47. // set, any unexpected type is mapped to `Invalid`, otherwise an invalid type
  48. // results in a compile error.
  49. //
  50. // The `Self` parameter is an implementation detail to allow `ForImpl` to be
  51. // defined after this template, and should not be specified.
  52. template <typename IdT, bool AllowInvalid = false, typename Self = TypeEnum>
  53. static constexpr auto For = Self::template ForImpl<IdT, AllowInvalid>();
  54. // This bool indicates whether the specified type corresponds to a value in
  55. // this enum.
  56. template <typename IdT>
  57. static constexpr bool Contains = For<IdT, true>.is_valid();
  58. // Explicitly convert from the raw enum type.
  59. explicit constexpr TypeEnum(RawEnumType value) : value_(value) {}
  60. // Implicitly convert to the raw enum type, for use in `switch`.
  61. //
  62. // NOLINTNEXTLINE(google-explicit-constructor)
  63. constexpr operator RawEnumType() const { return value_; }
  64. // Conversion to bool is deleted to prevent direct use in an `if` condition
  65. // instead of comparing with another value.
  66. explicit operator bool() const = delete;
  67. // Returns the raw enum value.
  68. constexpr auto ToRaw() const -> RawEnumType { return value_; }
  69. // Returns a value that can be used as an array index. Returned value will be
  70. // < NumValues.
  71. constexpr auto ToIndex() const -> size_t {
  72. return static_cast<size_t>(value_);
  73. }
  74. // Returns whether this is a valid value, not `Invalid`.
  75. constexpr auto is_valid() const -> bool {
  76. return value_ != RawEnumType::Invalid;
  77. }
  78. auto Print(llvm::raw_ostream& out) const -> void {
  79. out << "IdKind(";
  80. if (value_ == RawEnumType::None) {
  81. out << "None";
  82. } else {
  83. static constexpr std::array<llvm::StringLiteral, sizeof...(Types)> Names =
  84. {
  85. Types::Label...,
  86. };
  87. out << Names[static_cast<int>(value_)];
  88. }
  89. out << ")";
  90. }
  91. private:
  92. // Translates a type to its enum value, or `Invalid`.
  93. template <typename IdT, bool AllowInvalid>
  94. static constexpr auto ForImpl() -> TypeEnum {
  95. // A bool for each type saying whether it matches. The result is the index
  96. // of the first `true` in this list. If none matches, then the result is the
  97. // length of the list, which is mapped to `Invalid`.
  98. constexpr bool TypeMatches[] = {std::same_as<IdT, Types>...};
  99. constexpr int Index =
  100. std::find(TypeMatches, TypeMatches + NumTypes, true) - TypeMatches;
  101. static_assert(Index != NumTypes || AllowInvalid,
  102. "Unexpected type passed to TypeEnum::For<...>");
  103. return TypeEnum(static_cast<RawEnumType>(Index));
  104. }
  105. RawEnumType value_;
  106. };
  107. // An enum of all the ID types used as instruction operands.
  108. //
  109. // As instruction operands, the types listed here can appear as fields of typed
  110. // instructions (`toolchain/sem_ir/typed_insts.h`) and must implement the
  111. // `FromRaw` and `ToRaw` protocol in `SemIR::Inst`. In most cases this is done
  112. // by inheriting from `IdBase` or `IndexBase`.
  113. //
  114. // clang-format off: We want one per line.
  115. using IdKind = TypeEnum<
  116. // From base/value_store.h.
  117. FloatId,
  118. IntId,
  119. RealId,
  120. StringLiteralValueId,
  121. // From sem_ir/ids.h.
  122. AbsoluteInstBlockId,
  123. AbsoluteInstId,
  124. AnyRawId,
  125. AssociatedConstantId,
  126. BoolValue,
  127. CallParamIndex,
  128. ClassId,
  129. CompileTimeBindIndex,
  130. ConstantId,
  131. DeclInstBlockId,
  132. DestInstId,
  133. ElementIndex,
  134. EntityNameId,
  135. ExprRegionId,
  136. FacetTypeId,
  137. FloatKind,
  138. FunctionId,
  139. GenericId,
  140. ImplId,
  141. ImportIRId,
  142. ImportIRInstId,
  143. InstBlockId,
  144. InstId,
  145. InterfaceId,
  146. IntKind,
  147. LabelId,
  148. LibraryNameId,
  149. LocId,
  150. MetaInstId,
  151. NameId,
  152. NameScopeId,
  153. SpecificId,
  154. SpecificInterfaceId,
  155. StructTypeFieldsId,
  156. TypeInstId>;
  157. // clang-format on
  158. } // namespace Carbon::SemIR
  159. #endif // CARBON_TOOLCHAIN_SEM_IR_ID_KIND_H_