type.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  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_TYPE_H_
  5. #define CARBON_TOOLCHAIN_SEM_IR_TYPE_H_
  6. #include "llvm/ADT/STLExtras.h"
  7. #include "toolchain/base/shared_value_stores.h"
  8. #include "toolchain/sem_ir/constant.h"
  9. #include "toolchain/sem_ir/ids.h"
  10. #include "toolchain/sem_ir/inst.h"
  11. #include "toolchain/sem_ir/type_info.h"
  12. namespace Carbon::SemIR {
  13. #define CARBON_TYPE_QUALIFIERS(X) \
  14. X(Const) \
  15. X(MaybeUnformed) \
  16. X(Partial)
  17. CARBON_DEFINE_RAW_ENUM_MASK(TypeQualifiers, uint8_t) {
  18. CARBON_TYPE_QUALIFIERS(CARBON_RAW_ENUM_MASK_ENUMERATOR)
  19. };
  20. // Represents a set of keyword modifiers, using a separate bit per modifier.
  21. class TypeQualifiers : public CARBON_ENUM_MASK_BASE(TypeQualifiers) {
  22. public:
  23. CARBON_TYPE_QUALIFIERS(CARBON_ENUM_MASK_CONSTANT_DECL)
  24. };
  25. #define CARBON_TYPE_QUALIFIERS_WITH_TYPE(X) \
  26. CARBON_ENUM_MASK_CONSTANT_DEFINITION(TypeQualifiers, X)
  27. CARBON_TYPE_QUALIFIERS(CARBON_TYPE_QUALIFIERS_WITH_TYPE)
  28. #undef CARBON_TYPE_QUALIFIERS_WITH_TYPE
  29. // Provides a ValueStore wrapper with an API specific to types.
  30. class TypeStore : public Yaml::Printable<TypeStore> {
  31. public:
  32. // Used to return information about an integer type in `GetIntTypeInfo`.
  33. struct IntTypeInfo {
  34. bool is_signed;
  35. IntId bit_width;
  36. };
  37. explicit TypeStore(File* file) : file_(file) {}
  38. // Returns the ID of the constant used to define the specified type.
  39. auto GetConstantId(TypeId type_id) const -> ConstantId {
  40. if (!type_id.has_value()) {
  41. // TODO: Investigate replacing this with a CHECK or returning `None`.
  42. return ConstantId::NotConstant;
  43. }
  44. return type_id.AsConstantId();
  45. }
  46. // Returns the type ID for a constant that is a type value, i.e. it is a value
  47. // of type `TypeType`.
  48. //
  49. // Facet values are of the same typishness as types, but are not themselves
  50. // types, so they can not be passed here. They should be converted to a type
  51. // through an `as type` conversion, that is, to a value of type `TypeType`.
  52. auto GetTypeIdForTypeConstantId(ConstantId constant_id) const -> TypeId;
  53. // Like GetTypeIdForTypeConstantId() but returns None if the constant is not a
  54. // value of type `TypeType`.
  55. auto TryGetTypeIdForTypeConstantId(ConstantId constant_id) const -> TypeId;
  56. // Returns the type ID for an instruction whose constant value is a type
  57. // value, i.e. it is a value of type `TypeType`.
  58. //
  59. // Instructions whose values are facet values (see `FacetValue`) produce a
  60. // value of the same typishness as types, but which are themselves not types,
  61. // so they can not be passed here. They should be converted to a type through
  62. // an `as type` conversion, such as to a `FacetAccessType` instruction whose
  63. // value is of type `TypeType`.
  64. auto GetTypeIdForTypeInstId(InstId inst_id) const -> TypeId;
  65. auto GetTypeIdForTypeInstId(TypeInstId inst_id) const -> TypeId;
  66. // Converts an `InstId` to a `TypeInstId` of the same id value. This process
  67. // involves checking that the type of the instruction's value is `TypeType`,
  68. // and then this check is encoded in the type system via `TypeInstId`.
  69. auto GetAsTypeInstId(InstId inst_id) const -> TypeInstId;
  70. // Returns the ID of the instruction used to define the specified type.
  71. auto GetTypeInstId(TypeId type_id) const -> TypeInstId;
  72. // Returns the instruction used to define the specified type.
  73. auto GetAsInst(TypeId type_id) const -> Inst;
  74. // Returns the unattached form of the given type.
  75. auto GetUnattachedType(TypeId type_id) const -> TypeId;
  76. // Converts an ArrayRef of `InstId`s to a range of `TypeInstId`s via
  77. // GetAsTypeInstId().
  78. auto GetBlockAsTypeInstIds(llvm::ArrayRef<InstId> array
  79. [[clang::lifetimebound]]) const -> auto {
  80. return llvm::map_range(array, [&](InstId type_inst_id) {
  81. return GetAsTypeInstId(type_inst_id);
  82. });
  83. }
  84. // Converts an ArrayRef of `InstId`s to a range of `TypeId`s via
  85. // GetTypeIdForTypeInstId().
  86. auto GetBlockAsTypeIds(llvm::ArrayRef<InstId> array
  87. [[clang::lifetimebound]]) const -> auto {
  88. return llvm::map_range(array, [&](InstId type_inst_id) {
  89. return GetTypeIdForTypeInstId(type_inst_id);
  90. });
  91. }
  92. // Returns whether the specified kind of instruction was used to define the
  93. // type.
  94. template <typename InstT>
  95. auto Is(TypeId type_id) const -> bool {
  96. return GetAsInst(type_id).Is<InstT>();
  97. }
  98. // Returns whether one of the specified kinds of instruction was used to
  99. // define the type.
  100. template <typename... InstTs>
  101. auto IsOneOf(TypeId type_id) const -> bool {
  102. return GetAsInst(type_id).IsOneOf<InstTs...>();
  103. }
  104. // Returns the instruction used to define the specified type, which is known
  105. // to be a particular kind of instruction.
  106. template <typename InstT>
  107. auto GetAs(TypeId type_id) const -> InstT {
  108. return GetAsInst(type_id).As<InstT>();
  109. }
  110. // Returns the instruction used to define the specified type, if it is of a
  111. // particular kind.
  112. template <typename InstT>
  113. auto TryGetAs(TypeId type_id) const -> std::optional<InstT> {
  114. return GetAsInst(type_id).TryAs<InstT>();
  115. }
  116. // Returns whether two type IDs represent the same type. This includes the
  117. // case where they might be in different generics and thus might have
  118. // different ConstantIds, but are still symbolically equal.
  119. auto AreEqualAcrossDeclarations(TypeId a, TypeId b) const -> bool {
  120. return GetTypeInstId(a) == GetTypeInstId(b);
  121. }
  122. // Gets the value representation to use for a type. This returns an
  123. // `None` type if the given type is not complete.
  124. auto GetValueRepr(TypeId type_id) const -> ValueRepr {
  125. if (auto type_info = complete_type_info_.Lookup(type_id)) {
  126. return type_info.value().value_repr;
  127. }
  128. return {.kind = ValueRepr::Unknown};
  129. }
  130. // Gets the `CompleteTypeInfo` for a type, with an empty value if the type is
  131. // not complete.
  132. auto GetCompleteTypeInfo(TypeId type_id) const -> CompleteTypeInfo {
  133. if (auto type_info = complete_type_info_.Lookup(type_id)) {
  134. return type_info.value();
  135. }
  136. return {.value_repr = {.kind = ValueRepr::Unknown}};
  137. }
  138. // Sets the `CompleteTypeInfo` associated with a type, marking it as complete.
  139. // This can be used with abstract types.
  140. auto SetComplete(TypeId type_id, const CompleteTypeInfo& info) -> void {
  141. CARBON_CHECK(info.value_repr.kind != ValueRepr::Unknown);
  142. auto insert_info = complete_type_info_.Insert(type_id, info);
  143. CARBON_CHECK(insert_info.is_inserted(), "Type {0} completed more than once",
  144. type_id);
  145. complete_types_.push_back(type_id);
  146. CARBON_CHECK(IsComplete(type_id));
  147. }
  148. // Get the object representation associated with a type. For a non-class type,
  149. // this is the type itself. `None` is returned if the object representation
  150. // cannot be determined because the type is not complete.
  151. auto GetObjectRepr(TypeId type_id) const -> TypeId;
  152. // Get the type that the given type adapts, or `None` if the type is not known
  153. // to be an adapter, including the case where the type is an incomplete class.
  154. auto GetAdaptedType(TypeId type_id) const -> TypeId;
  155. // Returns the non-adapter type that is compatible with the specified type.
  156. auto GetTransitiveAdaptedType(TypeId type_id) const -> TypeId;
  157. // Determines whether the given type is known to be complete. This does not
  158. // determine whether the type could be completed, only whether it has been.
  159. auto IsComplete(TypeId type_id) const -> bool {
  160. return complete_type_info_.Contains(type_id);
  161. }
  162. // Removes any top-level qualifiers from a type.
  163. auto GetUnqualifiedType(TypeId type_id) const -> TypeId {
  164. return GetUnqualifiedTypeAndQualifiers(type_id).first;
  165. }
  166. // Removes any top-level qualifiers from a type and returns the unqualified
  167. // type and qualifiers.
  168. auto GetUnqualifiedTypeAndQualifiers(TypeId type_id) const
  169. -> std::pair<TypeId, TypeQualifiers>;
  170. // Returns the non-adapter unqualified type that is compatible with the
  171. // specified type.
  172. auto GetTransitiveUnqualifiedAdaptedType(TypeId type_id) const
  173. -> std::pair<TypeId, TypeQualifiers>;
  174. // Determines whether the given type is a signed integer type. This includes
  175. // the case where the type is `Core.IntLiteral` or a class type whose object
  176. // representation is a signed integer type.
  177. auto IsSignedInt(TypeId int_type_id) const -> bool;
  178. // Returns integer type information from a type ID that is known to represent
  179. // an integer type. Abstracts away the difference between an `IntType`
  180. // instruction defined type, a singleton instruction defined type, and a class
  181. // adapting such a type. Uses IntId::None for types that have a
  182. // non-constant width and for IntLiteral.
  183. auto GetIntTypeInfo(TypeId int_type_id) const -> IntTypeInfo;
  184. // Similar to `GetIntTypeInfo`, except allows non-`IntType` types to be
  185. // handled.
  186. auto TryGetIntTypeInfo(TypeId int_type_id) const
  187. -> std::optional<IntTypeInfo>;
  188. // Returns whether `type_id` represents a valid facet type.
  189. auto IsFacetType(TypeId type_id) const -> bool {
  190. return type_id == TypeType::TypeId || Is<FacetType>(type_id);
  191. }
  192. // Returns whether `type_id` represents any kind of facet type, including the
  193. // error instruction, which can be used as a type and so should be treated as
  194. // a facet type in some contexts.
  195. auto IsFacetTypeOrError(TypeId type_id) const -> bool {
  196. return IsFacetType(type_id) || type_id == ErrorInst::TypeId;
  197. }
  198. // Returns a list of types that were completed in this file, in the order in
  199. // which they were completed. Earlier types in this list cannot contain
  200. // instances of later types.
  201. auto complete_types() const -> llvm::ArrayRef<TypeId> {
  202. return complete_types_;
  203. }
  204. auto OutputYaml() const -> Yaml::OutputMapping {
  205. return Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) {
  206. for (auto type_id : complete_types_) {
  207. auto info = GetCompleteTypeInfo(type_id);
  208. map.Add(PrintToString(type_id),
  209. Yaml::OutputMapping([&](Yaml::OutputMapping::Map map2) {
  210. map2.Add("value_repr", Yaml::OutputScalar(info.value_repr));
  211. if (info.abstract_class_id.has_value()) {
  212. map2.Add("abstract_class_id",
  213. Yaml::OutputScalar(info.abstract_class_id));
  214. }
  215. }));
  216. }
  217. });
  218. }
  219. auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
  220. -> void {
  221. mem_usage.Collect(MemUsage::ConcatLabel(label, "complete_type_info_"),
  222. complete_type_info_);
  223. mem_usage.Collect(MemUsage::ConcatLabel(label, "complete_types_"),
  224. complete_types_);
  225. }
  226. private:
  227. File* file_;
  228. Map<TypeId, CompleteTypeInfo> complete_type_info_;
  229. llvm::SmallVector<TypeId> complete_types_;
  230. };
  231. // Returns the scrutinee type of `type_id`, which must be a `PatternType`.
  232. auto ExtractScrutineeType(const File& sem_ir, TypeId type_id) -> TypeId;
  233. } // namespace Carbon::SemIR
  234. #endif // CARBON_TOOLCHAIN_SEM_IR_TYPE_H_