| //===--- GenericParamList.h - Generic parameter list AST --------*- C++ -*-===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2018 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 GenericParamList class, and related classes. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SWIFT_GENERIC_PARAM_LIST_H |
| #define SWIFT_GENERIC_PARAM_LIST_H |
| |
| #include "swift/AST/Decl.h" |
| #include "swift/AST/LayoutConstraint.h" |
| #include "swift/Basic/SourceLoc.h" |
| #include "llvm/ADT/StringRef.h" |
| |
| namespace swift { |
| |
| class ASTPrinter; |
| class TypeRepr; |
| |
| enum class RequirementReprKind : unsigned { |
| /// A type bound T : P, where T is a type that depends on a generic |
| /// parameter and P is some type that should bound T, either as a concrete |
| /// supertype or a protocol to which T must conform. |
| TypeConstraint, |
| |
| /// 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. |
| LayoutConstraint, |
| |
| // Note: there is code that packs this enum in a 2-bit bitfield. Audit users |
| // when adding enumerators. |
| }; |
| |
| /// A single requirement in a 'where' clause, which places additional |
| /// restrictions on the generic parameters or associated types of a generic |
| /// function, type, or protocol. |
| /// |
| /// This always represents a requirement spelled in the source code. It is |
| /// never generated implicitly. |
| /// |
| /// \c GenericParamList assumes these are POD-like. |
| |
| class RequirementRepr { |
| SourceLoc SeparatorLoc; |
| RequirementReprKind Kind : 2; |
| bool Invalid : 1; |
| TypeRepr *FirstType; |
| |
| /// The second element represents the right-hand side of the constraint. |
| /// It can be e.g. a type or a layout constraint. |
| union { |
| TypeRepr *SecondType; |
| LayoutConstraintLoc SecondLayout; |
| }; |
| |
| /// Set during deserialization; used to print out the requirements accurately |
| /// for the generated interface. |
| StringRef AsWrittenString; |
| |
| RequirementRepr(SourceLoc SeparatorLoc, RequirementReprKind Kind, |
| TypeRepr *FirstType, TypeRepr *SecondType) |
| : SeparatorLoc(SeparatorLoc), Kind(Kind), Invalid(false), |
| FirstType(FirstType), SecondType(SecondType) { } |
| |
| RequirementRepr(SourceLoc SeparatorLoc, RequirementReprKind Kind, |
| TypeRepr *FirstType, LayoutConstraintLoc SecondLayout) |
| : SeparatorLoc(SeparatorLoc), Kind(Kind), Invalid(false), |
| FirstType(FirstType), SecondLayout(SecondLayout) { } |
| |
| void printImpl(ASTPrinter &OS) const; |
| |
| public: |
| /// Construct a new type-constraint requirement. |
| /// |
| /// \param Subject The type that must conform to the given protocol or |
| /// composition, or be a subclass of the given class type. |
| /// \param ColonLoc The location of the ':', or an invalid location if |
| /// this requirement was implied. |
| /// \param Constraint The protocol or protocol composition to which the |
| /// subject must conform, or superclass from which the subject must inherit. |
| static RequirementRepr getTypeConstraint(TypeRepr *Subject, |
| SourceLoc ColonLoc, |
| TypeRepr *Constraint) { |
| return { ColonLoc, RequirementReprKind::TypeConstraint, Subject, Constraint }; |
| } |
| |
| /// Construct a new same-type requirement. |
| /// |
| /// \param FirstType The first type. |
| /// \param EqualLoc The location of the '==' in the same-type constraint, or |
| /// an invalid location if this requirement was implied. |
| /// \param SecondType The second type. |
| static RequirementRepr getSameType(TypeRepr *FirstType, |
| SourceLoc EqualLoc, |
| TypeRepr *SecondType) { |
| return { EqualLoc, RequirementReprKind::SameType, FirstType, SecondType }; |
| } |
| |
| /// Construct a new layout-constraint requirement. |
| /// |
| /// \param Subject The type that must conform to the given layout |
| /// requirement. |
| /// \param ColonLoc The location of the ':', or an invalid location if |
| /// this requirement was implied. |
| /// \param Layout The layout requirement to which the |
| /// subject must conform. |
| static RequirementRepr getLayoutConstraint(TypeRepr *Subject, |
| SourceLoc ColonLoc, |
| LayoutConstraintLoc Layout) { |
| return {ColonLoc, RequirementReprKind::LayoutConstraint, Subject, |
| Layout}; |
| } |
| |
| /// Determine the kind of requirement |
| RequirementReprKind getKind() const { return Kind; } |
| |
| /// Determine whether this requirement is invalid. |
| bool isInvalid() const { return Invalid; } |
| |
| /// Mark this requirement invalid. |
| void setInvalid() { Invalid = true; } |
| |
| /// For a type-bound requirement, return the subject of the |
| /// conformance relationship. |
| TypeRepr *getSubjectRepr() const { |
| assert(getKind() == RequirementReprKind::TypeConstraint || |
| getKind() == RequirementReprKind::LayoutConstraint); |
| return FirstType; |
| } |
| |
| /// For a type-bound requirement, return the protocol or to which |
| /// the subject conforms or superclass it inherits. |
| TypeRepr *getConstraintRepr() const { |
| assert(getKind() == RequirementReprKind::TypeConstraint); |
| return SecondType; |
| } |
| |
| LayoutConstraint getLayoutConstraint() const { |
| assert(getKind() == RequirementReprKind::LayoutConstraint); |
| return SecondLayout.getLayoutConstraint(); |
| } |
| |
| LayoutConstraintLoc &getLayoutConstraintLoc() { |
| assert(getKind() == RequirementReprKind::LayoutConstraint); |
| return SecondLayout; |
| } |
| |
| const LayoutConstraintLoc &getLayoutConstraintLoc() const { |
| assert(getKind() == RequirementReprKind::LayoutConstraint); |
| return SecondLayout; |
| } |
| |
| /// Retrieve the first type of a same-type requirement. |
| TypeRepr *getFirstTypeRepr() const { |
| assert(getKind() == RequirementReprKind::SameType); |
| return FirstType; |
| } |
| |
| /// Retrieve the second type of a same-type requirement. |
| TypeRepr *getSecondTypeRepr() const { |
| assert(getKind() == RequirementReprKind::SameType); |
| return SecondType; |
| } |
| |
| /// Retrieve the location of the ':' or '==' in an explicitly-written |
| /// conformance or same-type requirement respectively. |
| SourceLoc getSeparatorLoc() const { |
| return SeparatorLoc; |
| } |
| |
| SourceRange getSourceRange() const; |
| |
| /// Retrieve the first or subject type representation from the \c repr, |
| /// or \c nullptr if \c repr is null. |
| static TypeRepr *getFirstTypeRepr(const RequirementRepr *repr) { |
| if (!repr) return nullptr; |
| return repr->FirstType; |
| } |
| |
| /// Retrieve the second or constraint type representation from the \c repr, |
| /// or \c nullptr if \c repr is null. |
| static TypeRepr *getSecondTypeRepr(const RequirementRepr *repr) { |
| if (!repr) return nullptr; |
| assert(repr->getKind() == RequirementReprKind::TypeConstraint || |
| repr->getKind() == RequirementReprKind::SameType); |
| return repr->SecondType; |
| } |
| |
| SWIFT_DEBUG_DUMP; |
| void print(raw_ostream &OS) const; |
| void print(ASTPrinter &Printer) const; |
| }; |
| |
| using GenericParamSource = PointerUnion<GenericContext *, GenericParamList *>; |
| |
| /// GenericParamList - A list of generic parameters that is part of a generic |
| /// function or type, along with extra requirements placed on those generic |
| /// parameters and types derived from them. |
| class GenericParamList final : |
| private llvm::TrailingObjects<GenericParamList, GenericTypeParamDecl *> { |
| friend TrailingObjects; |
| |
| SourceRange Brackets; |
| unsigned NumParams; |
| SourceLoc WhereLoc; |
| MutableArrayRef<RequirementRepr> Requirements; |
| |
| GenericParamList *OuterParameters; |
| |
| GenericParamList(SourceLoc LAngleLoc, |
| ArrayRef<GenericTypeParamDecl *> Params, |
| SourceLoc WhereLoc, |
| MutableArrayRef<RequirementRepr> Requirements, |
| SourceLoc RAngleLoc); |
| |
| // Don't copy. |
| GenericParamList(const GenericParamList &) = delete; |
| GenericParamList &operator=(const GenericParamList &) = delete; |
| |
| public: |
| /// create - Create a new generic parameter list within the given AST context. |
| /// |
| /// \param Context The ASTContext in which the generic parameter list will |
| /// be allocated. |
| /// \param LAngleLoc The location of the opening angle bracket ('<') |
| /// \param Params The list of generic parameters, which will be copied into |
| /// ASTContext-allocated memory. |
| /// \param RAngleLoc The location of the closing angle bracket ('>') |
| static GenericParamList *create(ASTContext &Context, |
| SourceLoc LAngleLoc, |
| ArrayRef<GenericTypeParamDecl *> Params, |
| SourceLoc RAngleLoc); |
| |
| /// create - Create a new generic parameter list and "where" clause within |
| /// the given AST context. |
| /// |
| /// \param Context The ASTContext in which the generic parameter list will |
| /// be allocated. |
| /// \param LAngleLoc The location of the opening angle bracket ('<') |
| /// \param Params The list of generic parameters, which will be copied into |
| /// ASTContext-allocated memory. |
| /// \param WhereLoc The location of the 'where' keyword, if any. |
| /// \param Requirements The list of requirements, which will be copied into |
| /// ASTContext-allocated memory. |
| /// \param RAngleLoc The location of the closing angle bracket ('>') |
| static GenericParamList *create(const ASTContext &Context, |
| SourceLoc LAngleLoc, |
| ArrayRef<GenericTypeParamDecl *> Params, |
| SourceLoc WhereLoc, |
| ArrayRef<RequirementRepr> Requirements, |
| SourceLoc RAngleLoc); |
| |
| MutableArrayRef<GenericTypeParamDecl *> getParams() { |
| return {getTrailingObjects<GenericTypeParamDecl *>(), NumParams}; |
| } |
| |
| ArrayRef<GenericTypeParamDecl *> getParams() const { |
| return {getTrailingObjects<GenericTypeParamDecl *>(), NumParams}; |
| } |
| |
| using iterator = GenericTypeParamDecl **; |
| using const_iterator = const GenericTypeParamDecl * const *; |
| |
| unsigned size() const { return NumParams; } |
| iterator begin() { return getParams().begin(); } |
| iterator end() { return getParams().end(); } |
| const_iterator begin() const { return getParams().begin(); } |
| const_iterator end() const { return getParams().end(); } |
| |
| /// Retrieve the location of the 'where' keyword, or an invalid |
| /// location if 'where' was not present. |
| SourceLoc getWhereLoc() const { return WhereLoc; } |
| |
| /// Retrieve the set of additional requirements placed on these |
| /// generic parameters and types derived from them. |
| /// |
| /// This list may contain both explicitly-written requirements as well as |
| /// implicitly-generated requirements, and may be non-empty even if no |
| /// 'where' keyword is present. |
| MutableArrayRef<RequirementRepr> getRequirements() { return Requirements; } |
| |
| /// Retrieve the set of additional requirements placed on these |
| /// generic parameters and types derived from them. |
| /// |
| /// This list may contain both explicitly-written requirements as well as |
| /// implicitly-generated requirements, and may be non-empty even if no |
| /// 'where' keyword is present. |
| ArrayRef<RequirementRepr> getRequirements() const { return Requirements; } |
| |
| /// Retrieve the outer generic parameter list. |
| /// |
| /// This is used for extensions of nested types, and in SIL mode, where a |
| /// single lexical context can have multiple logical generic parameter |
| /// lists. |
| GenericParamList *getOuterParameters() const { return OuterParameters; } |
| |
| /// Set the outer generic parameter list. See \c getOuterParameters |
| /// for more information. |
| void setOuterParameters(GenericParamList *Outer) { OuterParameters = Outer; } |
| |
| void setDeclContext(DeclContext *dc); |
| |
| SourceLoc getLAngleLoc() const { return Brackets.Start; } |
| SourceLoc getRAngleLoc() const { return Brackets.End; } |
| |
| SourceRange getSourceRange() const { return Brackets; } |
| |
| /// Retrieve the source range covering the where clause. |
| SourceRange getWhereClauseSourceRange() const { |
| if (WhereLoc.isInvalid()) |
| return SourceRange(); |
| |
| if (Requirements.empty()) |
| return WhereLoc; |
| |
| auto endLoc = Requirements.back().getSourceRange().End; |
| return SourceRange(WhereLoc, endLoc); |
| } |
| |
| /// Configure the depth of the generic parameters in this list. |
| void setDepth(unsigned depth); |
| |
| /// Create a copy of the generic parameter list and all of its generic |
| /// parameter declarations. The copied generic parameters are re-parented |
| /// to the given DeclContext. |
| GenericParamList *clone(DeclContext *dc) const; |
| |
| void print(raw_ostream &OS) const; |
| SWIFT_DEBUG_DUMP; |
| |
| bool walk(ASTWalker &walker); |
| |
| /// Finds a generic parameter declaration by name. This should only |
| /// be used from the SIL parser. |
| GenericTypeParamDecl *lookUpGenericParam(Identifier name) const; |
| }; |
| |
| /// A trailing where clause. |
| class alignas(RequirementRepr) TrailingWhereClause final : |
| private llvm::TrailingObjects<TrailingWhereClause, RequirementRepr> { |
| friend TrailingObjects; |
| |
| SourceLoc WhereLoc; |
| SourceLoc EndLoc; |
| |
| /// The number of requirements. The actual requirements are tail-allocated. |
| unsigned NumRequirements; |
| |
| TrailingWhereClause(SourceLoc whereLoc, SourceLoc endLoc, |
| ArrayRef<RequirementRepr> requirements); |
| |
| public: |
| /// Create a new trailing where clause with the given set of requirements. |
| static TrailingWhereClause *create(ASTContext &ctx, |
| SourceLoc whereLoc, SourceLoc endLoc, |
| ArrayRef<RequirementRepr> requirements); |
| |
| /// Retrieve the location of the 'where' keyword. |
| SourceLoc getWhereLoc() const { return WhereLoc; } |
| |
| /// Retrieve the set of requirements. |
| MutableArrayRef<RequirementRepr> getRequirements() { |
| return {getTrailingObjects<RequirementRepr>(), NumRequirements}; |
| } |
| |
| /// Retrieve the set of requirements. |
| ArrayRef<RequirementRepr> getRequirements() const { |
| return {getTrailingObjects<RequirementRepr>(), NumRequirements}; |
| } |
| |
| /// Compute the source range containing this trailing where clause. |
| SourceRange getSourceRange() const { |
| return SourceRange(WhereLoc, EndLoc); |
| } |
| |
| void print(llvm::raw_ostream &OS, bool printWhereKeyword) const; |
| |
| }; |
| |
| } // namespace swift |
| |
| #endif // SWIFT_GENERIC_PARAM_LIST_H |