| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- // 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_CHECK_TYPE_STRUCTURE_H_
- #define CARBON_TOOLCHAIN_CHECK_TYPE_STRUCTURE_H_
- #include <algorithm>
- #include "common/ostream.h"
- #include "llvm/ADT/SmallVector.h"
- #include "toolchain/check/context.h"
- #include "toolchain/check/scope_index.h"
- #include "toolchain/sem_ir/ids.h"
- namespace Carbon::Check {
- // The "type structure" for an impl declaration.
- //
- // See
- // https://docs.carbon-lang.dev/docs/design/generics/overview.html#parameterized-impl-declarations.
- //
- // Type structures are ordered, and a type structure that is ordered higher is a
- // better, more specified, match.
- class TypeStructure : public Printable<TypeStructure> {
- public:
- // TypeStructure is a pretty heavy data structure, avoid accidental copies.
- // TODO: Add a Clone() method if we want to make a copy of this in the future.
- TypeStructure(TypeStructure&&) noexcept = default;
- auto operator=(TypeStructure&&) noexcept -> TypeStructure& = default;
- enum class CompareTest {
- // Test whether `this` has the same structure as `other`, or `this` is
- // strictly more specific (has more concrete values) than `other` while
- // maintaining a compatible structure.
- //
- // If false, they can not possibly match with `this` being a lookup query
- // and `other` being an `impl`.
- IsEqualToOrMoreSpecificThan,
- // Tests whether there is a possible query that could match both `this` and
- // `other`, in which case we say `this` has overlap with `other`.
- HasOverlap,
- };
- // Compares the structure of `this` and `other`, and returns whether the
- // structures match according to the specified test.
- auto CompareStructure(CompareTest test, const TypeStructure& other) const
- -> bool;
- // Ordering of type structures. A lower value is a better match.
- // TODO: switch to operator<=> once we can depend on
- // std::lexicographical_compare_three_way (in particular, once we can
- // require clang-17 or newer, including in places like the GitHub test
- // runners).
- friend auto operator<(const TypeStructure& lhs, const TypeStructure& rhs)
- -> bool {
- return std::lexicographical_compare(
- lhs.symbolic_type_indices_.begin(), lhs.symbolic_type_indices_.end(),
- rhs.symbolic_type_indices_.begin(), rhs.symbolic_type_indices_.end(),
- [](int lhs_index, int rhs_index) {
- // A higher symbolic type index is a better match, so we need to
- // reverse the order.
- return rhs_index < lhs_index;
- });
- }
- // Equality of type structures. This compares that the structures are
- // identical, which is a stronger requirement than that they are ordered the
- // same.
- friend auto operator==(const TypeStructure& lhs, const TypeStructure& rhs)
- -> bool {
- return lhs.structure_ == rhs.structure_ &&
- lhs.concrete_types_ == rhs.concrete_types_;
- }
- auto Print(llvm::raw_ostream& out) const -> void {
- out << "TypeStructure = ";
- for (auto s : structure_) {
- switch (s) {
- case Structural::Concrete:
- out << 'c';
- break;
- case Structural::Symbolic:
- out << '?';
- break;
- case Structural::ConcreteOpenParen:
- out << "(";
- break;
- case Structural::ConcreteCloseParen:
- out << ')';
- break;
- }
- }
- }
- private:
- friend class TypeStructureBuilder;
- // Elements of the type structure, indicating the presence of a concrete or
- // symbolic element, and for aggregate concrete types (such as generic types),
- // nesting for the types inside.
- enum class Structural : uint8_t {
- // A concrete element in the type structure, such as `bool`.
- Concrete,
- // A concrete element in the type structure that contains nested types
- // within, such as `C(D)` for some classes C and D. It marks the start of
- // the nested and is paired with a ConcreteCloseParen at the end of the
- // nested types.
- ConcreteOpenParen,
- // Closes a ConcreteOpenParen for a concrete type with nested types.
- // Does not have its own concrete type.
- ConcreteCloseParen,
- // A symbolic element in the type structure. When matching type structures,
- // it represents a wildcard that matches against either a single `Concrete`
- // or `Symbolic`, or everything from a `ConcreteOpenParen` to its paired
- // `ConcreteCloseParen`.
- Symbolic,
- };
- // Marks a type of the named kind.
- enum class ConcreteTypeStart {
- // The type and bound will appear as other entries.
- Array,
- // The inner type will appear as another entry.
- Const,
- // The inner type will appear as another entry.
- MaybeUnformed,
- // The class type will appear as another entry.
- Partial,
- // The pointee type will appear as another entry.
- Pointer,
- // The field names and types will appear as other entries.
- Struct,
- // The type members (if any) will appear as other entries.
- Tuple,
- };
- // The `concrete_types_` tracks the specific concrete type for each
- // `Structural::Concrete` or `Structural::ConcreteOpenParen` in the type
- // structure.
- //
- // `ConstantId` is used strictly for non-type values. For types, `TypeId` is
- // used.
- //
- // `NameId` is used strictly for struct fields, as the field names are part of
- // the struct type.
- using ConcreteType =
- std::variant<ConcreteTypeStart, SemIR::ClassId, SemIR::ConstantId,
- SemIR::InterfaceId, SemIR::NameId, SemIR::TypeId>;
- TypeStructure(llvm::SmallVector<Structural> structure,
- llvm::SmallVector<int> symbolic_type_indices,
- llvm::SmallVector<ConcreteType> concrete_types)
- : structure_(std::move(structure)),
- symbolic_type_indices_(std::move(symbolic_type_indices)),
- concrete_types_(std::move(concrete_types)) {}
- // A helper for CompareStructure.
- static auto ConsumeRhsSymbolic(
- llvm::SmallVector<Structural>::const_iterator& lhs_cursor,
- llvm::SmallVector<ConcreteType>::const_iterator& lhs_concrete_cursor,
- llvm::SmallVector<Structural>::const_iterator& rhs_cursor) -> bool;
- // The structural position of concrete and symbolic constants in the type.
- llvm::SmallVector<Structural> structure_;
- // Indices of the symbolic entries in structure_.
- llvm::SmallVector<int> symbolic_type_indices_;
- // The related value for each `Concrete` and `ConcreteOpenParen` entry in
- // the type `structure_`, in the same order. See `ConcreteType`.
- llvm::SmallVector<ConcreteType> concrete_types_;
- };
- // Constructs the TypeStructure for a self type or facet value and an interface
- // constraint (e.g. `Iface(A, B(C))`), which represents the location of unknown
- // symbolic constants in the combined signature and which is ordered by them.
- //
- // Given `impl C as Z {}` the `self_const_id` would be a `C` and the interface
- // constraint would be `Z`.
- //
- // Returns nullopt if an ErrorInst is encountered in the self type or facet
- // value.
- auto BuildTypeStructure(Context& context, SemIR::InstId self_inst_id,
- SemIR::SpecificInterface interface)
- -> std::optional<TypeStructure>;
- } // namespace Carbon::Check
- #endif // CARBON_TOOLCHAIN_CHECK_TYPE_STRUCTURE_H_
|