| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
- // Exceptions. See /LICENSE for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- #ifndef CARBON_TOOLCHAIN_SEM_IR_TYPE_H_
- #define CARBON_TOOLCHAIN_SEM_IR_TYPE_H_
- #include "llvm/ADT/STLExtras.h"
- #include "toolchain/base/shared_value_stores.h"
- #include "toolchain/sem_ir/constant.h"
- #include "toolchain/sem_ir/ids.h"
- #include "toolchain/sem_ir/inst.h"
- #include "toolchain/sem_ir/type_info.h"
- namespace Carbon::SemIR {
- #define CARBON_TYPE_QUALIFIERS(X) \
- X(Const) \
- X(MaybeUnformed) \
- X(Partial)
- CARBON_DEFINE_RAW_ENUM_MASK(TypeQualifiers, uint8_t) {
- CARBON_TYPE_QUALIFIERS(CARBON_RAW_ENUM_MASK_ENUMERATOR)
- };
- // Represents a set of keyword modifiers, using a separate bit per modifier.
- class TypeQualifiers : public CARBON_ENUM_MASK_BASE(TypeQualifiers) {
- public:
- CARBON_TYPE_QUALIFIERS(CARBON_ENUM_MASK_CONSTANT_DECL)
- };
- #define CARBON_TYPE_QUALIFIERS_WITH_TYPE(X) \
- CARBON_ENUM_MASK_CONSTANT_DEFINITION(TypeQualifiers, X)
- CARBON_TYPE_QUALIFIERS(CARBON_TYPE_QUALIFIERS_WITH_TYPE)
- #undef CARBON_TYPE_QUALIFIERS_WITH_TYPE
- // Provides a ValueStore wrapper with an API specific to types.
- class TypeStore : public Yaml::Printable<TypeStore> {
- public:
- // Used to return information about an integer type in `GetIntTypeInfo`.
- struct IntTypeInfo {
- bool is_signed;
- IntId bit_width;
- };
- explicit TypeStore(File* file) : file_(file) {}
- // Returns the ID of the constant used to define the specified type.
- auto GetConstantId(TypeId type_id) const -> ConstantId {
- if (!type_id.has_value()) {
- // TODO: Investigate replacing this with a CHECK or returning `None`.
- return ConstantId::NotConstant;
- }
- return type_id.AsConstantId();
- }
- // Returns the type ID for a constant that is a type value, i.e. it is a value
- // of type `TypeType`.
- //
- // Facet values are of the same typishness as types, but are not themselves
- // types, so they can not be passed here. They should be converted to a type
- // through an `as type` conversion, that is, to a value of type `TypeType`.
- auto GetTypeIdForTypeConstantId(ConstantId constant_id) const -> TypeId;
- // Like GetTypeIdForTypeConstantId() but returns None if the constant is not a
- // value of type `TypeType`.
- auto TryGetTypeIdForTypeConstantId(ConstantId constant_id) const -> TypeId;
- // Returns the type ID for an instruction whose constant value is a type
- // value, i.e. it is a value of type `TypeType`.
- //
- // Instructions whose values are facet values (see `FacetValue`) produce a
- // value of the same typishness as types, but which are themselves not types,
- // so they can not be passed here. They should be converted to a type through
- // an `as type` conversion, such as to a `FacetAccessType` instruction whose
- // value is of type `TypeType`.
- auto GetTypeIdForTypeInstId(InstId inst_id) const -> TypeId;
- auto GetTypeIdForTypeInstId(TypeInstId inst_id) const -> TypeId;
- // Like GetTypeIdForTypeInstId() but returns None if the constant is not a
- // value of type `TypeType`.
- auto TryGetTypeIdForTypeInstId(InstId inst_id) const -> TypeId;
- // Converts an `InstId` to a `TypeInstId` of the same id value. This process
- // involves checking that the type of the instruction's value is `TypeType`,
- // and then this check is encoded in the type system via `TypeInstId`.
- auto GetAsTypeInstId(InstId inst_id) const -> TypeInstId;
- // Returns the ID of the instruction used to define the specified type.
- auto GetTypeInstId(TypeId type_id) const -> TypeInstId;
- // Returns the instruction used to define the specified type.
- auto GetAsInst(TypeId type_id) const -> Inst;
- // Returns the unattached form of the given type.
- auto GetUnattachedType(TypeId type_id) const -> TypeId;
- // Converts an ArrayRef of `InstId`s to a range of `TypeInstId`s via
- // GetAsTypeInstId().
- auto GetBlockAsTypeInstIds(llvm::ArrayRef<InstId> array
- [[clang::lifetimebound]]) const -> auto {
- return llvm::map_range(array, [&](InstId type_inst_id) {
- return GetAsTypeInstId(type_inst_id);
- });
- }
- // Converts an ArrayRef of `InstId`s to a range of `TypeId`s via
- // GetTypeIdForTypeInstId().
- auto GetBlockAsTypeIds(llvm::ArrayRef<InstId> array
- [[clang::lifetimebound]]) const -> auto {
- return llvm::map_range(array, [&](InstId type_inst_id) {
- return GetTypeIdForTypeInstId(type_inst_id);
- });
- }
- // Returns whether the specified kind of instruction was used to define the
- // type.
- template <typename InstT>
- auto Is(TypeId type_id) const -> bool {
- return GetAsInst(type_id).Is<InstT>();
- }
- // Returns whether one of the specified kinds of instruction was used to
- // define the type.
- template <typename... InstTs>
- auto IsOneOf(TypeId type_id) const -> bool {
- return GetAsInst(type_id).IsOneOf<InstTs...>();
- }
- // Returns the instruction used to define the specified type, which is known
- // to be a particular kind of instruction.
- template <typename InstT>
- auto GetAs(TypeId type_id) const -> InstT {
- return GetAsInst(type_id).As<InstT>();
- }
- // Returns the instruction used to define the specified type, if it is of a
- // particular kind.
- template <typename InstT>
- auto TryGetAs(TypeId type_id) const -> std::optional<InstT> {
- return GetAsInst(type_id).TryAs<InstT>();
- }
- // Like TryGetAs() but also handles the case where `type_id` has no value, and
- // then returns nullopt.
- template <typename InstT>
- auto TryGetAsIfValid(TypeId type_id) const -> std::optional<InstT> {
- if (!type_id.has_value()) {
- return {};
- }
- return GetAsInst(type_id).TryAs<InstT>();
- }
- // Returns whether two type IDs represent the same type. This includes the
- // case where they might be in different generics and thus might have
- // different ConstantIds, but are still symbolically equal.
- auto AreEqualAcrossDeclarations(TypeId a, TypeId b) const -> bool {
- return GetTypeInstId(a) == GetTypeInstId(b);
- }
- // Gets the value representation to use for a type. This returns an
- // `None` type if the given type is not complete.
- auto GetValueRepr(TypeId type_id) const -> ValueRepr {
- if (auto type_info = complete_type_info_.Lookup(type_id)) {
- return type_info.value().value_repr;
- }
- return {.kind = ValueRepr::Unknown};
- }
- // Gets the `CompleteTypeInfo` for a type, with an empty value if the type is
- // not complete.
- auto GetCompleteTypeInfo(TypeId type_id) const -> CompleteTypeInfo {
- if (auto type_info = complete_type_info_.Lookup(type_id)) {
- return type_info.value();
- }
- return {.value_repr = {.kind = ValueRepr::Unknown}};
- }
- // Sets the `CompleteTypeInfo` associated with a type, marking it as complete.
- // This can be used with abstract types.
- auto SetComplete(TypeId type_id, const CompleteTypeInfo& info) -> void {
- CARBON_CHECK(info.value_repr.kind != ValueRepr::Unknown);
- auto insert_info = complete_type_info_.Insert(type_id, info);
- CARBON_CHECK(insert_info.is_inserted(), "Type {0} completed more than once",
- type_id);
- complete_types_.push_back(type_id);
- CARBON_CHECK(IsComplete(type_id));
- }
- // Get the object representation associated with a type. For a non-class type,
- // this is the type itself. `None` is returned if the object representation
- // cannot be determined because the type is not complete.
- auto GetObjectRepr(TypeId type_id) const -> TypeId;
- // Get the type that the given type adapts, or `None` if the type is not known
- // to be an adapter, including the case where the type is an incomplete class.
- auto GetAdaptedType(TypeId type_id) const -> TypeId;
- // Returns the non-adapter type that is compatible with the specified type.
- auto GetTransitiveAdaptedType(TypeId type_id) const -> TypeId;
- // Determines whether the given type is known to be complete. This does not
- // determine whether the type could be completed, only whether it has been.
- auto IsComplete(TypeId type_id) const -> bool {
- return complete_type_info_.Contains(type_id);
- }
- // Removes any top-level qualifiers from a type.
- auto GetUnqualifiedType(TypeId type_id) const -> TypeId {
- return GetUnqualifiedTypeAndQualifiers(type_id).first;
- }
- // Removes any top-level qualifiers from a type and returns the unqualified
- // type and qualifiers.
- auto GetUnqualifiedTypeAndQualifiers(TypeId type_id) const
- -> std::pair<TypeId, TypeQualifiers>;
- // Returns the non-adapter unqualified type that is compatible with the
- // specified type.
- auto GetTransitiveUnqualifiedAdaptedType(TypeId type_id) const
- -> std::pair<TypeId, TypeQualifiers>;
- // Determines whether the given type is a signed integer type. This includes
- // the case where the type is `Core.IntLiteral` or a class type whose object
- // representation is a signed integer type.
- auto IsSignedInt(TypeId int_type_id) const -> bool;
- // Returns integer type information from a type ID that is known to represent
- // an integer type. Abstracts away the difference between an `IntType`
- // instruction defined type, a singleton instruction defined type, and a class
- // adapting such a type. Uses IntId::None for types that have a
- // non-constant width and for IntLiteral.
- auto GetIntTypeInfo(TypeId int_type_id) const -> IntTypeInfo;
- // Similar to `GetIntTypeInfo`, except allows non-`IntType` types to be
- // handled.
- auto TryGetIntTypeInfo(TypeId int_type_id) const
- -> std::optional<IntTypeInfo>;
- // Returns whether `type_id` represents a valid facet type.
- auto IsFacetType(TypeId type_id) const -> bool {
- return type_id == TypeType::TypeId || Is<FacetType>(type_id);
- }
- // Returns whether `type_id` represents any kind of facet type, including the
- // error instruction, which can be used as a type and so should be treated as
- // a facet type in some contexts.
- auto IsFacetTypeOrError(TypeId type_id) const -> bool {
- return IsFacetType(type_id) || type_id == ErrorInst::TypeId;
- }
- // Returns a list of types that were completed in this file, in the order in
- // which they were completed. Earlier types in this list cannot contain
- // instances of later types.
- auto complete_types() const -> llvm::ArrayRef<TypeId> {
- return complete_types_;
- }
- auto OutputYaml() const -> Yaml::OutputMapping {
- return Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) {
- for (auto type_id : complete_types_) {
- auto info = GetCompleteTypeInfo(type_id);
- map.Add(PrintToString(type_id),
- Yaml::OutputMapping([&](Yaml::OutputMapping::Map map2) {
- map2.Add("value_repr", Yaml::OutputScalar(info.value_repr));
- map2.Add(
- "object_layout",
- Yaml::OutputMapping([&](Yaml::OutputMapping::Map map3) {
- map3.Add("size",
- Yaml::OutputScalar(info.object_layout.size));
- map3.Add(
- "alignment",
- Yaml::OutputScalar(info.object_layout.alignment));
- }));
- if (info.abstract_class_id.has_value()) {
- map2.Add("abstract_class_id",
- Yaml::OutputScalar(info.abstract_class_id));
- }
- }));
- }
- });
- }
- auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
- -> void {
- mem_usage.Collect(MemUsage::ConcatLabel(label, "complete_type_info_"),
- complete_type_info_);
- mem_usage.Collect(MemUsage::ConcatLabel(label, "complete_types_"),
- complete_types_);
- }
- private:
- File* file_;
- Map<TypeId, CompleteTypeInfo> complete_type_info_;
- llvm::SmallVector<TypeId> complete_types_;
- };
- // Returns the scrutinee type of `type_id`, which must be a `PatternType`.
- auto ExtractScrutineeType(const File& sem_ir, TypeId type_id) -> TypeId;
- } // namespace Carbon::SemIR
- #endif // CARBON_TOOLCHAIN_SEM_IR_TYPE_H_
|