type_structure.h 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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_CHECK_TYPE_STRUCTURE_H_
  5. #define CARBON_TOOLCHAIN_CHECK_TYPE_STRUCTURE_H_
  6. #include <algorithm>
  7. #include "common/ostream.h"
  8. #include "llvm/ADT/SmallVector.h"
  9. #include "toolchain/check/context.h"
  10. #include "toolchain/check/scope_index.h"
  11. #include "toolchain/sem_ir/ids.h"
  12. namespace Carbon::Check {
  13. // The "type structure" for an impl declaration.
  14. //
  15. // See
  16. // https://docs.carbon-lang.dev/docs/design/generics/overview.html#parameterized-impl-declarations.
  17. //
  18. // Type structures are ordered, and a type structure that is ordered higher is a
  19. // better, more specified, match.
  20. class TypeStructure : public Printable<TypeStructure> {
  21. public:
  22. // TypeStructure is a pretty heavy data structure, avoid accidental copies.
  23. // TODO: Add a Clone() method if we want to make a copy of this in the future.
  24. TypeStructure(TypeStructure&&) noexcept = default;
  25. auto operator=(TypeStructure&&) noexcept -> TypeStructure& = default;
  26. enum class CompareTest {
  27. // Test whether `this` has the same structure as `other`, or `this` is
  28. // strictly more specific (has more concrete values) than `other` while
  29. // maintaining a compatible structure.
  30. //
  31. // If false, they can not possibly match with `this` being a lookup query
  32. // and `other` being an `impl`.
  33. IsEqualToOrMoreSpecificThan,
  34. // Tests whether there is a possible query that could match both `this` and
  35. // `other`, in which case we say `this` has overlap with `other`.
  36. HasOverlap,
  37. };
  38. // Compares the structure of `this` and `other`, and returns whether the
  39. // structures match according to the specified test.
  40. auto CompareStructure(CompareTest test, const TypeStructure& other) const
  41. -> bool;
  42. // Ordering of type structures. A lower value is a better match.
  43. // TODO: switch to operator<=> once we can depend on
  44. // std::lexicographical_compare_three_way (in particular, once we can
  45. // require clang-17 or newer, including in places like the GitHub test
  46. // runners).
  47. friend auto operator<(const TypeStructure& lhs, const TypeStructure& rhs)
  48. -> bool {
  49. return std::lexicographical_compare(
  50. lhs.symbolic_type_indices_.begin(), lhs.symbolic_type_indices_.end(),
  51. rhs.symbolic_type_indices_.begin(), rhs.symbolic_type_indices_.end(),
  52. [](int lhs_index, int rhs_index) {
  53. // A higher symbolic type index is a better match, so we need to
  54. // reverse the order.
  55. return rhs_index < lhs_index;
  56. });
  57. }
  58. // Equality of type structures. This compares that the structures are
  59. // identical, which is a stronger requirement than that they are ordered the
  60. // same.
  61. friend auto operator==(const TypeStructure& lhs, const TypeStructure& rhs)
  62. -> bool {
  63. return lhs.structure_ == rhs.structure_ &&
  64. lhs.concrete_types_ == rhs.concrete_types_;
  65. }
  66. auto Print(llvm::raw_ostream& out) const -> void {
  67. out << "TypeStructure = ";
  68. for (auto s : structure_) {
  69. switch (s) {
  70. case Structural::Concrete:
  71. out << 'c';
  72. break;
  73. case Structural::Symbolic:
  74. out << '?';
  75. break;
  76. case Structural::ConcreteOpenParen:
  77. out << "(";
  78. break;
  79. case Structural::ConcreteCloseParen:
  80. out << ')';
  81. break;
  82. }
  83. }
  84. }
  85. private:
  86. friend class TypeStructureBuilder;
  87. // Elements of the type structure, indicating the presence of a concrete or
  88. // symbolic element, and for aggregate concrete types (such as generic types),
  89. // nesting for the types inside.
  90. enum class Structural : uint8_t {
  91. // A concrete element in the type structure, such as `bool`.
  92. Concrete,
  93. // A concrete element in the type structure that contains nested types
  94. // within, such as `C(D)` for some classes C and D. It marks the start of
  95. // the nested and is paired with a ConcreteCloseParen at the end of the
  96. // nested types.
  97. ConcreteOpenParen,
  98. // Closes a ConcreteOpenParen for a concrete type with nested types.
  99. // Does not have its own concrete type.
  100. ConcreteCloseParen,
  101. // A symbolic element in the type structure. When matching type structures,
  102. // it represents a wildcard that matches against either a single `Concrete`
  103. // or `Symbolic`, or everything from a `ConcreteOpenParen` to its paired
  104. // `ConcreteCloseParen`.
  105. Symbolic,
  106. };
  107. // Marks a type of the named kind.
  108. enum class ConcreteTypeStart {
  109. // The type and bound will appear as other entries.
  110. Array,
  111. // The inner type will appear as another entry.
  112. Const,
  113. // The inner type will appear as another entry.
  114. MaybeUnformed,
  115. // The class type will appear as another entry.
  116. Partial,
  117. // The pointee type will appear as another entry.
  118. Pointer,
  119. // The field names and types will appear as other entries.
  120. Struct,
  121. // The type members (if any) will appear as other entries.
  122. Tuple,
  123. };
  124. // The `concrete_types_` tracks the specific concrete type for each
  125. // `Structural::Concrete` or `Structural::ConcreteOpenParen` in the type
  126. // structure.
  127. //
  128. // `ConstantId` is used strictly for non-type values. For types, `TypeId` is
  129. // used.
  130. //
  131. // `NameId` is used strictly for struct fields, as the field names are part of
  132. // the struct type.
  133. using ConcreteType =
  134. std::variant<ConcreteTypeStart, SemIR::ClassId, SemIR::ConstantId,
  135. SemIR::InterfaceId, SemIR::NameId, SemIR::TypeId>;
  136. TypeStructure(llvm::SmallVector<Structural> structure,
  137. llvm::SmallVector<int> symbolic_type_indices,
  138. llvm::SmallVector<ConcreteType> concrete_types)
  139. : structure_(std::move(structure)),
  140. symbolic_type_indices_(std::move(symbolic_type_indices)),
  141. concrete_types_(std::move(concrete_types)) {}
  142. // A helper for CompareStructure.
  143. static auto ConsumeRhsSymbolic(
  144. llvm::SmallVector<Structural>::const_iterator& lhs_cursor,
  145. llvm::SmallVector<ConcreteType>::const_iterator& lhs_concrete_cursor,
  146. llvm::SmallVector<Structural>::const_iterator& rhs_cursor) -> bool;
  147. // The structural position of concrete and symbolic constants in the type.
  148. llvm::SmallVector<Structural> structure_;
  149. // Indices of the symbolic entries in structure_.
  150. llvm::SmallVector<int> symbolic_type_indices_;
  151. // The related value for each `Concrete` and `ConcreteOpenParen` entry in
  152. // the type `structure_`, in the same order. See `ConcreteType`.
  153. llvm::SmallVector<ConcreteType> concrete_types_;
  154. };
  155. // Constructs the TypeStructure for a self type or facet value and an interface
  156. // constraint (e.g. `Iface(A, B(C))`), which represents the location of unknown
  157. // symbolic constants in the combined signature and which is ordered by them.
  158. //
  159. // Given `impl C as Z {}` the `self_const_id` would be a `C` and the interface
  160. // constraint would be `Z`.
  161. //
  162. // Returns nullopt if an ErrorInst is encountered in the self type or facet
  163. // value.
  164. auto BuildTypeStructure(Context& context, SemIR::InstId self_inst_id,
  165. SemIR::SpecificInterface interface)
  166. -> std::optional<TypeStructure>;
  167. } // namespace Carbon::Check
  168. #endif // CARBON_TOOLCHAIN_CHECK_TYPE_STRUCTURE_H_