type_structure.h 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  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/sem_ir/ids.h"
  11. namespace Carbon::Check {
  12. // The "type structure" for an impl declaration.
  13. //
  14. // See
  15. // https://docs.carbon-lang.dev/docs/design/generics/overview.html#parameterized-impl-declarations.
  16. //
  17. // Type structures are ordered, and a type structure that is ordered higher is a
  18. // better, more specified, match.
  19. class TypeStructure : public Printable<TypeStructure> {
  20. public:
  21. enum class CompareTest {
  22. // Test whether `this` has the same structure as `other`, or `this` is
  23. // strictly more specific (has more concrete values) than `other` while
  24. // maintaining a compatible structure.
  25. //
  26. // If false, they can not possibly match with `this` being a lookup query
  27. // and `other` being an `impl`.
  28. IsEqualToOrMoreSpecificThan,
  29. // Tests whether there is a possible query that could match both `this` and
  30. // `other`, in which case we say `this` has overlap with `other`.
  31. HasOverlap,
  32. };
  33. // Compares the structure of `this` and `other`, and returns whether the
  34. // structures match according to the specified test.
  35. auto CompareStructure(CompareTest test, const TypeStructure& other) const
  36. -> bool;
  37. // Ordering of type structures. A lower value is a better match.
  38. // TODO: switch to operator<=> once we can depend on
  39. // std::lexicographical_compare_three_way (in particular, once we can
  40. // require clang-17 or newer, including in places like the GitHub test
  41. // runners).
  42. friend auto operator<(const TypeStructure& lhs, const TypeStructure& rhs)
  43. -> bool {
  44. return std::lexicographical_compare(
  45. lhs.symbolic_type_indices_.begin(), lhs.symbolic_type_indices_.end(),
  46. rhs.symbolic_type_indices_.begin(), rhs.symbolic_type_indices_.end(),
  47. [](int lhs_index, int rhs_index) {
  48. // A higher symbolic type index is a better match, so we need to
  49. // reverse the order.
  50. return rhs_index < lhs_index;
  51. });
  52. }
  53. // Equality of type structures. This compares that the structures are
  54. // identical, which is a stronger requirement than that they are ordered the
  55. // same.
  56. friend auto operator==(const TypeStructure& lhs, const TypeStructure& rhs)
  57. -> bool {
  58. return lhs.structure_ == rhs.structure_ &&
  59. lhs.concrete_types_ == rhs.concrete_types_;
  60. }
  61. auto Print(llvm::raw_ostream& out) const -> void {
  62. out << "TypeStructure = ";
  63. for (auto s : structure_) {
  64. switch (s) {
  65. case Structural::Concrete:
  66. out << 'c';
  67. break;
  68. case Structural::Symbolic:
  69. out << '?';
  70. break;
  71. case Structural::ConcreteOpenParen:
  72. out << "(";
  73. break;
  74. case Structural::ConcreteCloseParen:
  75. out << ')';
  76. break;
  77. }
  78. }
  79. }
  80. private:
  81. friend class TypeStructureBuilder;
  82. // Elements of the type structure, indicating the presence of a concrete or
  83. // symbolic element, and for aggregate concrete types (such as generic types),
  84. // nesting for the types inside.
  85. enum class Structural : uint8_t {
  86. // A concrete element in the type structure, such as `bool`.
  87. Concrete,
  88. // A concrete element in the type structure that contains nested types
  89. // within, such as `C(D)` for some classes C and D. It marks the start of
  90. // the nested and is paired with a ConcreteCloseParen at the end of the
  91. // nested types.
  92. ConcreteOpenParen,
  93. // Closes a ConcreteOpenParen for a concrete type with nested types.
  94. // Does not have its own concrete type.
  95. ConcreteCloseParen,
  96. // A symbolic element in the type structure. When matching type structures,
  97. // it represents a wildcard that matches against either a single `Concrete`
  98. // or `Symbolic`, or everything from a `ConcreteOpenParen` to its paired
  99. // `ConcreteCloseParen`.
  100. Symbolic,
  101. };
  102. // Marks an array type. The type and bound will appear as other entries.
  103. struct ConcreteArrayType {
  104. friend auto operator==(ConcreteArrayType /*lhs*/, ConcreteArrayType /*rhs*/)
  105. -> bool = default;
  106. };
  107. // Marks a pointer type. The pointee type will appear as another entry.
  108. struct ConcretePointerType {
  109. friend auto operator==(ConcretePointerType /*lhs*/,
  110. ConcretePointerType /*rhs*/) -> bool = default;
  111. };
  112. // Marks a struct type. The field names and types will appear as other
  113. // entries.
  114. struct ConcreteStructType {
  115. friend auto operator==(ConcreteStructType /*lhs*/,
  116. ConcreteStructType /*rhs*/) -> bool = default;
  117. };
  118. // Marks a tuple type. The type members (if any) will appear as other entries.
  119. struct ConcreteTupleType {
  120. friend auto operator==(ConcreteTupleType /*lhs*/, ConcreteTupleType /*rhs*/)
  121. -> bool = default;
  122. };
  123. // The `concrete_types_` tracks the specific concrete type for each
  124. // `Structural::Concrete` or `Structural::ConcreteOpenParen` in the type
  125. // structure.
  126. //
  127. // `ConstantId` is used strictly for non-type values. For types, `TypeId` is
  128. // used.
  129. //
  130. // `NameId` is used strictly for struct fields, as the field names are part of
  131. // the struct type.
  132. using ConcreteType =
  133. std::variant<ConcreteArrayType, ConcretePointerType, ConcreteStructType,
  134. ConcreteTupleType, 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 values 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 values 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_