| //===--- Requirement.h - Swift Requirement ASTs -----------------*- C++ -*-===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines the Requirement class and subclasses. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SWIFT_AST_REQUIREMENT_H |
| #define SWIFT_AST_REQUIREMENT_H |
| |
| #include "swift/AST/Type.h" |
| #include "swift/Basic/Debug.h" |
| #include "llvm/ADT/Hashing.h" |
| #include "llvm/ADT/PointerIntPair.h" |
| #include "llvm/Support/ErrorHandling.h" |
| |
| namespace swift { |
| |
| /// Describes the kind of a requirement that occurs within a requirements |
| /// clause. |
| enum class RequirementKind : unsigned { |
| /// A conformance requirement T : P, where T is a type that depends |
| /// on a generic parameter and P is a protocol to which T must conform. |
| Conformance, |
| /// A superclass requirement T : C, where T is a type that depends |
| /// on a generic parameter and C is a concrete class type which T must |
| /// equal or be a subclass of. |
| Superclass, |
| /// A same-type requirement T == U, where T and U are types that shall be |
| /// equivalent. |
| SameType, |
| /// A layout bound T : L, where T is a type that depends on a generic |
| /// parameter and L is some layout specification that should bound T. |
| Layout, |
| |
| // Note: there is code that packs this enum in a 2-bit bitfield. Audit users |
| // when adding enumerators. |
| }; |
| |
| /// A single requirement placed on the type parameters (or associated |
| /// types thereof) of a |
| class Requirement { |
| llvm::PointerIntPair<Type, 3, RequirementKind> FirstTypeAndKind; |
| /// The second element of the requirement. Its content is dependent |
| /// on the requirement kind. |
| /// The payload of the following enum should always match the kind! |
| /// Any access to the fields of this enum should first check if the |
| /// requested access matches the kind of the requirement. |
| union { |
| Type SecondType; |
| LayoutConstraint SecondLayout; |
| }; |
| |
| public: |
| /// Create a conformance or same-type requirement. |
| Requirement(RequirementKind kind, Type first, Type second) |
| : FirstTypeAndKind(first, kind), SecondType(second) { |
| assert(first); |
| assert(second); |
| } |
| |
| /// Create a layout constraint requirement. |
| Requirement(RequirementKind kind, Type first, LayoutConstraint second) |
| : FirstTypeAndKind(first, kind), SecondLayout(second) { |
| assert(first); |
| assert(second); |
| } |
| |
| /// Determine the kind of requirement. |
| RequirementKind getKind() const { return FirstTypeAndKind.getInt(); } |
| |
| /// Retrieve the first type. |
| Type getFirstType() const { |
| return FirstTypeAndKind.getPointer(); |
| } |
| |
| /// Retrieve the second type. |
| Type getSecondType() const { |
| assert(getKind() != RequirementKind::Layout); |
| return SecondType; |
| } |
| |
| /// Subst the types involved in this requirement. |
| /// |
| /// The \c args arguments are passed through to Type::subst. This doesn't |
| /// touch the superclasses, protocols or layout constraints. |
| template <typename... Args> |
| Optional<Requirement> subst(Args &&... args) const { |
| auto newFirst = getFirstType().subst(std::forward<Args>(args)...); |
| if (newFirst->hasError()) |
| return None; |
| |
| switch (getKind()) { |
| case RequirementKind::Conformance: |
| case RequirementKind::Superclass: |
| case RequirementKind::SameType: { |
| auto newSecond = getSecondType().subst(std::forward<Args>(args)...); |
| if (newSecond->hasError()) |
| return None; |
| return Requirement(getKind(), newFirst, newSecond); |
| } |
| case RequirementKind::Layout: |
| return Requirement(getKind(), newFirst, getLayoutConstraint()); |
| } |
| |
| llvm_unreachable("Unhandled RequirementKind in switch."); |
| } |
| |
| /// Retrieve the layout constraint. |
| LayoutConstraint getLayoutConstraint() const { |
| assert(getKind() == RequirementKind::Layout); |
| return SecondLayout; |
| } |
| |
| /// Whether this requirement is in its canonical form. |
| bool isCanonical() const; |
| |
| /// Get the canonical form of this requirement. |
| Requirement getCanonical() const; |
| |
| SWIFT_DEBUG_DUMP; |
| void dump(raw_ostream &out) const; |
| void print(raw_ostream &os, const PrintOptions &opts) const; |
| void print(ASTPrinter &printer, const PrintOptions &opts) const; |
| |
| friend llvm::hash_code hash_value(const Requirement &requirement) { |
| using llvm::hash_value; |
| |
| llvm::hash_code first = |
| hash_value(requirement.FirstTypeAndKind.getOpaqueValue()); |
| llvm::hash_code second; |
| switch (requirement.getKind()) { |
| case RequirementKind::Conformance: |
| case RequirementKind::Superclass: |
| case RequirementKind::SameType: |
| second = hash_value(requirement.getSecondType().getPointer()); |
| break; |
| |
| case RequirementKind::Layout: |
| second = hash_value(requirement.getLayoutConstraint()); |
| break; |
| } |
| |
| return llvm::hash_combine(first, second); |
| } |
| |
| friend bool operator==(const Requirement &lhs, const Requirement &rhs) { |
| if (lhs.FirstTypeAndKind.getOpaqueValue() |
| != rhs.FirstTypeAndKind.getOpaqueValue()) |
| return false; |
| |
| switch (lhs.getKind()) { |
| case RequirementKind::Conformance: |
| case RequirementKind::Superclass: |
| case RequirementKind::SameType: |
| return lhs.getSecondType().getPointer() == |
| rhs.getSecondType().getPointer(); |
| |
| case RequirementKind::Layout: |
| return lhs.getLayoutConstraint() == rhs.getLayoutConstraint(); |
| } |
| llvm_unreachable("Unhandled RequirementKind in switch"); |
| } |
| }; |
| |
| inline void simple_display(llvm::raw_ostream &out, const Requirement &req) { |
| req.print(out, PrintOptions()); |
| } |
| |
| } // end namespace swift |
| |
| #endif |