type_structure.h 7.0 KB

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