| //===--- Stmt.h - Swift Language Statement 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 Stmt class and subclasses. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SWIFT_AST_STMT_H |
| #define SWIFT_AST_STMT_H |
| |
| #include "swift/AST/ASTNode.h" |
| #include "swift/AST/Availability.h" |
| #include "swift/AST/AvailabilitySpec.h" |
| #include "swift/AST/ConcreteDeclRef.h" |
| #include "swift/AST/IfConfigClause.h" |
| #include "swift/AST/TypeAlignments.h" |
| #include "swift/Basic/Debug.h" |
| #include "swift/Basic/NullablePtr.h" |
| #include "llvm/Support/TrailingObjects.h" |
| |
| namespace swift { |
| |
| class AnyPattern; |
| class ASTContext; |
| class ASTWalker; |
| class Decl; |
| class Expr; |
| class FuncDecl; |
| class Pattern; |
| class PatternBindingDecl; |
| class VarDecl; |
| class CaseStmt; |
| class DoCatchStmt; |
| class SwitchStmt; |
| |
| enum class StmtKind { |
| #define STMT(ID, PARENT) ID, |
| #define LAST_STMT(ID) Last_Stmt = ID, |
| #define STMT_RANGE(Id, FirstId, LastId) \ |
| First_##Id##Stmt = FirstId, Last_##Id##Stmt = LastId, |
| #include "swift/AST/StmtNodes.def" |
| }; |
| enum : unsigned { NumStmtKindBits = |
| countBitsUsed(static_cast<unsigned>(StmtKind::Last_Stmt)) }; |
| |
| /// Stmt - Base class for all statements in swift. |
| class alignas(8) Stmt { |
| Stmt(const Stmt&) = delete; |
| Stmt& operator=(const Stmt&) = delete; |
| |
| protected: |
| union { uint64_t OpaqueBits; |
| |
| SWIFT_INLINE_BITFIELD_BASE(Stmt, bitmax(NumStmtKindBits,8) + 1, |
| /// Kind - The subclass of Stmt that this is. |
| Kind : bitmax(NumStmtKindBits,8), |
| |
| /// Implicit - Whether this statement is implicit. |
| Implicit : 1 |
| ); |
| |
| SWIFT_INLINE_BITFIELD_FULL(BraceStmt, Stmt, 32, |
| : NumPadBits, |
| NumElements : 32 |
| ); |
| |
| SWIFT_INLINE_BITFIELD_FULL(CaseStmt, Stmt, 32, |
| : NumPadBits, |
| NumPatterns : 32 |
| ); |
| |
| SWIFT_INLINE_BITFIELD_EMPTY(LabeledStmt, Stmt); |
| |
| SWIFT_INLINE_BITFIELD_FULL(DoCatchStmt, LabeledStmt, 32, |
| : NumPadBits, |
| NumCatches : 32 |
| ); |
| |
| SWIFT_INLINE_BITFIELD_FULL(SwitchStmt, LabeledStmt, 32, |
| : NumPadBits, |
| CaseCount : 32 |
| ); |
| |
| SWIFT_INLINE_BITFIELD_FULL(YieldStmt, Stmt, 32, |
| : NumPadBits, |
| NumYields : 32 |
| ); |
| |
| } Bits; |
| |
| /// Return the given value for the 'implicit' flag if present, or if None, |
| /// return true if the location is invalid. |
| static bool getDefaultImplicitFlag(Optional<bool> implicit, SourceLoc keyLoc){ |
| return implicit.hasValue() ? *implicit : keyLoc.isInvalid(); |
| } |
| |
| public: |
| Stmt(StmtKind kind, bool implicit) { |
| Bits.OpaqueBits = 0; |
| Bits.Stmt.Kind = static_cast<unsigned>(kind); |
| Bits.Stmt.Implicit = implicit; |
| } |
| |
| StmtKind getKind() const { return StmtKind(Bits.Stmt.Kind); } |
| |
| /// Retrieve the name of the given statement kind. |
| /// |
| /// This name should only be used for debugging dumps and other |
| /// developer aids, and should never be part of a diagnostic or exposed |
| /// to the user of the compiler in any way. |
| static StringRef getKindName(StmtKind kind); |
| |
| /// Return the location of the start of the statement. |
| SourceLoc getStartLoc() const; |
| |
| /// Return the location of the end of the statement. |
| SourceLoc getEndLoc() const; |
| |
| SourceRange getSourceRange() const; |
| SourceLoc TrailingSemiLoc; |
| |
| /// isImplicit - Determines whether this statement was implicitly-generated, |
| /// rather than explicitly written in the AST. |
| bool isImplicit() const { return Bits.Stmt.Implicit; } |
| |
| /// walk - This recursively walks the AST rooted at this statement. |
| Stmt *walk(ASTWalker &walker); |
| Stmt *walk(ASTWalker &&walker) { return walk(walker); } |
| |
| SWIFT_DEBUG_DUMP; |
| void dump(raw_ostream &OS, const ASTContext *Ctx = nullptr, unsigned Indent = 0) const; |
| |
| // Only allow allocation of Exprs using the allocator in ASTContext |
| // or by doing a placement new. |
| void *operator new(size_t Bytes, ASTContext &C, |
| unsigned Alignment = alignof(Stmt)); |
| |
| // Make vanilla new/delete illegal for Stmts. |
| void *operator new(size_t Bytes) throw() = delete; |
| void operator delete(void *Data) throw() = delete; |
| void *operator new(size_t Bytes, void *Mem) throw() = delete; |
| }; |
| |
| /// BraceStmt - A brace enclosed sequence of expressions, stmts, or decls, like |
| /// { var x = 10; print(10) }. |
| class BraceStmt final : public Stmt, |
| private llvm::TrailingObjects<BraceStmt, ASTNode> { |
| friend TrailingObjects; |
| |
| SourceLoc LBLoc; |
| SourceLoc RBLoc; |
| |
| BraceStmt(SourceLoc lbloc, ArrayRef<ASTNode> elements,SourceLoc rbloc, |
| Optional<bool> implicit); |
| |
| public: |
| static BraceStmt *create(ASTContext &ctx, SourceLoc lbloc, |
| ArrayRef<ASTNode> elements, |
| SourceLoc rbloc, |
| Optional<bool> implicit = None); |
| |
| SourceLoc getLBraceLoc() const { return LBLoc; } |
| SourceLoc getRBraceLoc() const { return RBLoc; } |
| |
| SourceRange getSourceRange() const { return SourceRange(LBLoc, RBLoc); } |
| |
| bool empty() const { return getNumElements() == 0; } |
| unsigned getNumElements() const { return Bits.BraceStmt.NumElements; } |
| |
| ASTNode getFirstElement() const { return getElements().front(); } |
| ASTNode getLastElement() const { return getElements().back(); } |
| |
| void setFirstElement(ASTNode node) { getElements().front() = node; } |
| void setLastElement(ASTNode node) { getElements().back() = node; } |
| |
| /// The elements contained within the BraceStmt. |
| MutableArrayRef<ASTNode> getElements() { |
| return {getTrailingObjects<ASTNode>(), Bits.BraceStmt.NumElements}; |
| } |
| |
| /// The elements contained within the BraceStmt (const version). |
| ArrayRef<ASTNode> getElements() const { |
| return {getTrailingObjects<ASTNode>(), Bits.BraceStmt.NumElements}; |
| } |
| |
| static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Brace; } |
| }; |
| |
| /// ReturnStmt - A return statement. The result is optional; "return" without |
| /// an expression is semantically equivalent to "return ()". |
| /// return 42 |
| class ReturnStmt : public Stmt { |
| SourceLoc ReturnLoc; |
| Expr *Result; |
| |
| public: |
| ReturnStmt(SourceLoc ReturnLoc, Expr *Result, |
| Optional<bool> implicit = None) |
| : Stmt(StmtKind::Return, getDefaultImplicitFlag(implicit, ReturnLoc)), |
| ReturnLoc(ReturnLoc), Result(Result) {} |
| |
| SourceLoc getReturnLoc() const { return ReturnLoc; } |
| |
| SourceLoc getStartLoc() const; |
| SourceLoc getEndLoc() const; |
| |
| bool hasResult() const { return Result != 0; } |
| Expr *getResult() const { |
| assert(Result && "ReturnStmt doesn't have a result"); |
| return Result; |
| } |
| void setResult(Expr *e) { Result = e; } |
| |
| static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Return;} |
| }; |
| |
| /// YieldStmt - A yield statement. The yield-values sequence is not optional, |
| /// but the parentheses are. |
| /// yield 42 |
| class YieldStmt final |
| : public Stmt, private llvm::TrailingObjects<YieldStmt, Expr*> { |
| friend TrailingObjects; |
| |
| SourceLoc YieldLoc; |
| SourceLoc LPLoc; |
| SourceLoc RPLoc; |
| |
| YieldStmt(SourceLoc yieldLoc, SourceLoc lpLoc, ArrayRef<Expr *> yields, |
| SourceLoc rpLoc, Optional<bool> implicit = None) |
| : Stmt(StmtKind::Yield, getDefaultImplicitFlag(implicit, yieldLoc)), |
| YieldLoc(yieldLoc), LPLoc(lpLoc), RPLoc(rpLoc) { |
| Bits.YieldStmt.NumYields = yields.size(); |
| memcpy(getMutableYields().data(), yields.data(), |
| yields.size() * sizeof(Expr*)); |
| } |
| |
| public: |
| static YieldStmt *create(const ASTContext &ctx, SourceLoc yieldLoc, |
| SourceLoc lp, ArrayRef<Expr*> yields, SourceLoc rp, |
| Optional<bool> implicit = None); |
| |
| SourceLoc getYieldLoc() const { return YieldLoc; } |
| SourceLoc getLParenLoc() const { return LPLoc; } |
| SourceLoc getRParenLoc() const { return RPLoc; } |
| |
| SourceLoc getStartLoc() const { return YieldLoc; } |
| SourceLoc getEndLoc() const; |
| |
| ArrayRef<Expr*> getYields() const { |
| return {getTrailingObjects<Expr*>(), Bits.YieldStmt.NumYields}; |
| } |
| MutableArrayRef<Expr*> getMutableYields() { |
| return {getTrailingObjects<Expr*>(), Bits.YieldStmt.NumYields}; |
| } |
| |
| static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Yield; } |
| }; |
| |
| /// DeferStmt - A 'defer' statement. This runs the substatement it contains |
| /// when the enclosing scope is exited. |
| /// |
| /// defer { cleanUp() } |
| /// |
| /// The AST representation for a defer statement is a bit weird. We model this |
| /// as if they wrote: |
| /// |
| /// func tmpClosure() { body } |
| /// tmpClosure() // This is emitted on each path that needs to run this. |
| /// |
| /// As such, the body of the 'defer' is actually type checked within the |
| /// closure's DeclContext. We do this because of unfortunateness in SILGen, |
| /// some expressions (e.g. OpenExistentialExpr) cannot be multiply emitted in a |
| /// composable way. When this gets fixed, patches r27767 and r27768 can be |
| /// reverted to go back to the simpler and more obvious representation. |
| /// |
| class DeferStmt : public Stmt { |
| SourceLoc DeferLoc; |
| |
| /// This is the bound temp function. |
| FuncDecl *tempDecl; |
| |
| /// This is the invocation of the closure, which is to be emitted on any error |
| /// paths. |
| Expr *callExpr; |
| |
| public: |
| DeferStmt(SourceLoc DeferLoc, |
| FuncDecl *tempDecl, Expr *callExpr) |
| : Stmt(StmtKind::Defer, /*implicit*/false), |
| DeferLoc(DeferLoc), tempDecl(tempDecl), |
| callExpr(callExpr) {} |
| |
| SourceLoc getDeferLoc() const { return DeferLoc; } |
| |
| SourceLoc getStartLoc() const { return DeferLoc; } |
| SourceLoc getEndLoc() const; |
| |
| FuncDecl *getTempDecl() const { return tempDecl; } |
| Expr *getCallExpr() const { return callExpr; } |
| void setCallExpr(Expr *E) { callExpr = E; } |
| |
| /// Dig the original user's body of the defer out for AST fidelity. |
| BraceStmt *getBodyAsWritten() const; |
| |
| static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Defer; } |
| }; |
| |
| |
| /// An expression that guards execution based on whether the run-time |
| /// configuration supports a given API, e.g., |
| /// #available(OSX >= 10.9, iOS >= 7.0). |
| class alignas(8) PoundAvailableInfo final : |
| private llvm::TrailingObjects<PoundAvailableInfo, AvailabilitySpec *> { |
| friend TrailingObjects; |
| |
| SourceLoc PoundLoc; |
| SourceLoc LParenLoc; |
| SourceLoc RParenLoc; |
| |
| // The number of queries tail allocated after this object. |
| unsigned NumQueries; |
| |
| /// The version range when this query will return true. This value is |
| /// filled in by Sema. |
| VersionRange AvailableRange; |
| |
| /// For zippered builds, this is the version range for the target variant |
| /// that must hold for the query to return true. For example, when |
| /// compiling with target x86_64-macosx10.15 and target-variant |
| /// x86_64-ios13.0 a query of #available(macOS 10.22, iOS 20.0, *) will |
| /// have a variant range of [20.0, +inf). |
| /// This is filled in by Sema. |
| VersionRange VariantAvailableRange; |
| |
| PoundAvailableInfo(SourceLoc PoundLoc, SourceLoc LParenLoc, |
| ArrayRef<AvailabilitySpec *> queries, SourceLoc RParenLoc) |
| : PoundLoc(PoundLoc), LParenLoc(LParenLoc), RParenLoc(RParenLoc), |
| NumQueries(queries.size()), AvailableRange(VersionRange::empty()), |
| VariantAvailableRange(VersionRange::empty()) { |
| std::uninitialized_copy(queries.begin(), queries.end(), |
| getTrailingObjects<AvailabilitySpec *>()); |
| } |
| |
| public: |
| static PoundAvailableInfo *create(ASTContext &ctx, SourceLoc PoundLoc, |
| SourceLoc LParenLoc, |
| ArrayRef<AvailabilitySpec *> queries, |
| SourceLoc RParenLoc); |
| |
| ArrayRef<AvailabilitySpec *> getQueries() const { |
| return llvm::makeArrayRef(getTrailingObjects<AvailabilitySpec *>(), |
| NumQueries); |
| } |
| |
| SourceLoc getLParenLoc() const { return LParenLoc; } |
| SourceLoc getRParenLoc() const { return RParenLoc; } |
| |
| SourceLoc getStartLoc() const { return PoundLoc; } |
| SourceLoc getEndLoc() const; |
| SourceLoc getLoc() const { return PoundLoc; } |
| SourceRange getSourceRange() const { return SourceRange(getStartLoc(), |
| getEndLoc()); } |
| |
| const VersionRange &getAvailableRange() const { return AvailableRange; } |
| void setAvailableRange(const VersionRange &Range) { AvailableRange = Range; } |
| |
| const VersionRange &getVariantAvailableRange() const { |
| return VariantAvailableRange; |
| } |
| void setVariantAvailableRange(const VersionRange &Range) { |
| VariantAvailableRange = Range; |
| } |
| }; |
| |
| |
| /// This represents an entry in an "if" or "while" condition. Pattern bindings |
| /// can bind any number of names in the pattern binding decl, and may have an |
| /// associated where clause. When "if let" is involved, an arbitrary number of |
| /// pattern bindings and conditional expressions are permitted, e.g.: |
| /// |
| /// if let x = ..., y = ... where x > y, |
| /// let z = ... |
| /// which would be represented as four StmtConditionElement entries, one for |
| /// the "x" binding, one for the "y" binding, one for the where clause, one for |
| /// "z"'s binding. A simple "if" statement is represented as a single binding. |
| /// |
| class StmtConditionElement { |
| /// If this is a pattern binding, it may be the first one in a declaration, in |
| /// which case this is the location of the var/let/case keyword. If this is |
| /// the second pattern (e.g. for 'y' in "var x = ..., y = ...") then this |
| /// location is invalid. |
| SourceLoc IntroducerLoc; |
| |
| /// In a pattern binding, this is pattern being matched. In the case of an |
| /// "implicit optional" pattern, the OptionalSome pattern is explicitly added |
| /// to this as an 'implicit' pattern. |
| Pattern *ThePattern = nullptr; |
| |
| /// This is either the boolean condition, the initializer for a pattern |
| /// binding, or the #available information. |
| llvm::PointerUnion<PoundAvailableInfo*, Expr *> CondInitOrAvailable; |
| |
| public: |
| StmtConditionElement() {} |
| StmtConditionElement(SourceLoc IntroducerLoc, Pattern *ThePattern, |
| Expr *Init) |
| : IntroducerLoc(IntroducerLoc), ThePattern(ThePattern), |
| CondInitOrAvailable(Init) {} |
| StmtConditionElement(Expr *cond) : CondInitOrAvailable(cond) {} |
| |
| StmtConditionElement(PoundAvailableInfo *Info) : CondInitOrAvailable(Info) {} |
| |
| SourceLoc getIntroducerLoc() const { return IntroducerLoc; } |
| void setIntroducerLoc(SourceLoc loc) { IntroducerLoc = loc; } |
| |
| /// ConditionKind - This indicates the sort of condition this is. |
| enum ConditionKind { |
| CK_Boolean, |
| CK_PatternBinding, |
| CK_Availability |
| }; |
| |
| ConditionKind getKind() const { |
| if (ThePattern) return CK_PatternBinding; |
| return CondInitOrAvailable.is<Expr*>() ? CK_Boolean : CK_Availability; |
| } |
| |
| /// Boolean Condition Accessors. |
| Expr *getBooleanOrNull() const { |
| return getKind() == CK_Boolean ? CondInitOrAvailable.get<Expr*>() : nullptr; |
| } |
| |
| Expr *getBoolean() const { |
| assert(getKind() == CK_Boolean && "Not a condition"); |
| return CondInitOrAvailable.get<Expr*>(); |
| } |
| void setBoolean(Expr *E) { |
| assert(getKind() == CK_Boolean && "Not a condition"); |
| CondInitOrAvailable = E; |
| } |
| |
| /// Pattern Binding Accessors. |
| Pattern *getPatternOrNull() const { |
| return ThePattern; |
| } |
| |
| Pattern *getPattern() const { |
| assert(getKind() == CK_PatternBinding && "Not a pattern binding condition"); |
| return ThePattern; |
| } |
| |
| void setPattern(Pattern *P) { |
| assert(getKind() == CK_PatternBinding && "Not a pattern binding condition"); |
| ThePattern = P; |
| } |
| |
| Expr *getInitializer() const { |
| assert(getKind() == CK_PatternBinding && "Not a pattern binding condition"); |
| return CondInitOrAvailable.get<Expr*>(); |
| } |
| void setInitializer(Expr *E) { |
| assert(getKind() == CK_PatternBinding && "Not a pattern binding condition"); |
| CondInitOrAvailable = E; |
| } |
| |
| // Availability Accessors |
| PoundAvailableInfo *getAvailability() const { |
| assert(getKind() == CK_Availability && "Not an #available condition"); |
| return CondInitOrAvailable.get<PoundAvailableInfo*>(); |
| } |
| |
| void setAvailability(PoundAvailableInfo *Info) { |
| assert(getKind() == CK_Availability && "Not an #available condition"); |
| CondInitOrAvailable = Info; |
| } |
| |
| SourceLoc getStartLoc() const; |
| SourceLoc getEndLoc() const; |
| SourceRange getSourceRange() const; |
| |
| /// Recursively walks the AST rooted at this statement condition element |
| StmtConditionElement *walk(ASTWalker &walker); |
| StmtConditionElement *walk(ASTWalker &&walker) { return walk(walker); } |
| }; |
| |
| struct LabeledStmtInfo { |
| Identifier Name; |
| SourceLoc Loc; |
| |
| // Evaluates to true if set. |
| operator bool() const { return !Name.empty(); } |
| }; |
| |
| /// LabeledStmt - Common base class between the labeled statements (loops and |
| /// switch). |
| class LabeledStmt : public Stmt { |
| LabeledStmtInfo LabelInfo; |
| protected: |
| SourceLoc getLabelLocOrKeywordLoc(SourceLoc L) const { |
| return LabelInfo ? LabelInfo.Loc : L; |
| } |
| public: |
| LabeledStmt(StmtKind Kind, bool Implicit, LabeledStmtInfo LabelInfo) |
| : Stmt(Kind, Implicit), LabelInfo(LabelInfo) {} |
| |
| LabeledStmtInfo getLabelInfo() const { return LabelInfo; } |
| void setLabelInfo(LabeledStmtInfo L) { LabelInfo = L; } |
| |
| /// Is this statement a valid target of "continue" if labeled? |
| /// |
| /// For the most part, non-looping constructs shouldn't be |
| /// continue-able, but we threw in "do" as a sop. |
| bool isPossibleContinueTarget() const; |
| |
| /// Is this statement a valid target of an unlabeled "break" or |
| /// "continue"? |
| /// |
| /// The nice, consistent language rule is that unlabeled "break" and |
| /// "continue" leave the innermost loop. We have to include |
| /// "switch" (for "break") for consistency with C: Swift doesn't |
| /// require "break" to leave a switch case, but it's still way too |
| /// similar to C's switch to allow different behavior for "break". |
| bool requiresLabelOnJump() const; |
| |
| static bool classof(const Stmt *S) { |
| return S->getKind() >= StmtKind::First_LabeledStmt && |
| S->getKind() <= StmtKind::Last_LabeledStmt; |
| } |
| }; |
| |
| |
| /// DoStmt - do statement, without any trailing clauses. |
| class DoStmt : public LabeledStmt { |
| SourceLoc DoLoc; |
| BraceStmt *Body; |
| |
| public: |
| DoStmt(LabeledStmtInfo labelInfo, SourceLoc doLoc, |
| BraceStmt *body, Optional<bool> implicit = None) |
| : LabeledStmt(StmtKind::Do, getDefaultImplicitFlag(implicit, doLoc), |
| labelInfo), |
| DoLoc(doLoc), Body(body) {} |
| |
| SourceLoc getDoLoc() const { return DoLoc; } |
| |
| SourceLoc getStartLoc() const { return getLabelLocOrKeywordLoc(DoLoc); } |
| SourceLoc getEndLoc() const { return Body->getEndLoc(); } |
| |
| BraceStmt *getBody() const { return Body; } |
| void setBody(BraceStmt *s) { Body = s; } |
| |
| static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Do; } |
| }; |
| |
| /// Either an "if let" case or a simple boolean expression can appear as the |
| /// condition of an 'if' or 'while' statement. |
| using StmtCondition = MutableArrayRef<StmtConditionElement>; |
| |
| /// This is the common base class between statements that can have labels, and |
| /// also have complex "if let" style conditions: 'if' and 'while'. |
| class LabeledConditionalStmt : public LabeledStmt { |
| StmtCondition Cond; |
| public: |
| LabeledConditionalStmt(StmtKind Kind, bool Implicit, |
| LabeledStmtInfo LabelInfo, StmtCondition Cond) |
| : LabeledStmt(Kind, Implicit, LabelInfo) { |
| setCond(Cond); |
| } |
| |
| StmtCondition getCond() const { return Cond; } |
| void setCond(StmtCondition e); |
| |
| static bool classof(const Stmt *S) { |
| return S->getKind() >= StmtKind::First_LabeledConditionalStmt && |
| S->getKind() <= StmtKind::Last_LabeledConditionalStmt; |
| } |
| }; |
| |
| |
| /// IfStmt - if/then/else statement. If no 'else' is specified, then the |
| /// ElseLoc location is not specified and the Else statement is null. After |
| /// type-checking, the condition is of type Builtin.Int1. |
| class IfStmt : public LabeledConditionalStmt { |
| SourceLoc IfLoc; |
| SourceLoc ElseLoc; |
| Stmt *Then; |
| Stmt *Else; |
| |
| public: |
| IfStmt(LabeledStmtInfo LabelInfo, SourceLoc IfLoc, StmtCondition Cond, |
| Stmt *Then, SourceLoc ElseLoc, Stmt *Else, |
| Optional<bool> implicit = None) |
| : LabeledConditionalStmt(StmtKind::If, |
| getDefaultImplicitFlag(implicit, IfLoc), |
| LabelInfo, Cond), |
| IfLoc(IfLoc), ElseLoc(ElseLoc), Then(Then), Else(Else) {} |
| |
| IfStmt(SourceLoc IfLoc, Expr *Cond, Stmt *Then, SourceLoc ElseLoc, |
| Stmt *Else, Optional<bool> implicit, ASTContext &Ctx); |
| |
| SourceLoc getIfLoc() const { return IfLoc; } |
| SourceLoc getElseLoc() const { return ElseLoc; } |
| |
| SourceLoc getStartLoc() const { |
| return getLabelLocOrKeywordLoc(IfLoc); |
| } |
| SourceLoc getEndLoc() const { |
| return (Else ? Else->getEndLoc() : Then->getEndLoc()); |
| } |
| |
| Stmt *getThenStmt() const { return Then; } |
| void setThenStmt(Stmt *s) { Then = s; } |
| |
| Stmt *getElseStmt() const { return Else; } |
| void setElseStmt(Stmt *s) { Else = s; } |
| |
| // Implement isa/cast/dyncast/etc. |
| static bool classof(const Stmt *S) { return S->getKind() == StmtKind::If; } |
| }; |
| |
| /// GuardStmt - 'guard' statement. Evaluate a condition and if it fails, run |
| /// its body. The body is always guaranteed to exit the current scope (or |
| /// abort), it never falls through. |
| /// |
| class GuardStmt : public LabeledConditionalStmt { |
| SourceLoc GuardLoc; |
| BraceStmt *Body; |
| |
| public: |
| GuardStmt(SourceLoc GuardLoc, StmtCondition Cond, |
| BraceStmt *Body, Optional<bool> implicit = None) |
| : LabeledConditionalStmt(StmtKind::Guard, |
| getDefaultImplicitFlag(implicit, GuardLoc), |
| LabeledStmtInfo(), Cond), |
| GuardLoc(GuardLoc), Body(Body) {} |
| |
| GuardStmt(SourceLoc GuardLoc, Expr *Cond, BraceStmt *Body, |
| Optional<bool> implicit, ASTContext &Ctx); |
| |
| SourceLoc getGuardLoc() const { return GuardLoc; } |
| |
| SourceLoc getStartLoc() const { |
| return getLabelLocOrKeywordLoc(GuardLoc); |
| } |
| SourceLoc getEndLoc() const { |
| return Body->getEndLoc(); |
| } |
| |
| BraceStmt *getBody() const { return Body; } |
| void setBody(BraceStmt *s) { Body = s; } |
| |
| // Implement isa/cast/dyncast/etc. |
| static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Guard; } |
| }; |
| |
| /// WhileStmt - while statement. After type-checking, the condition is of |
| /// type Builtin.Int1. |
| class WhileStmt : public LabeledConditionalStmt { |
| SourceLoc WhileLoc; |
| StmtCondition Cond; |
| Stmt *Body; |
| |
| public: |
| WhileStmt(LabeledStmtInfo LabelInfo, SourceLoc WhileLoc, StmtCondition Cond, |
| Stmt *Body, Optional<bool> implicit = None) |
| : LabeledConditionalStmt(StmtKind::While, |
| getDefaultImplicitFlag(implicit, WhileLoc), |
| LabelInfo, Cond), |
| WhileLoc(WhileLoc), Body(Body) {} |
| |
| SourceLoc getStartLoc() const { return getLabelLocOrKeywordLoc(WhileLoc); } |
| SourceLoc getEndLoc() const { return Body->getEndLoc(); } |
| SourceLoc getWhileLoc() const { return WhileLoc; } |
| |
| Stmt *getBody() const { return Body; } |
| void setBody(Stmt *s) { Body = s; } |
| |
| static bool classof(const Stmt *S) { return S->getKind() == StmtKind::While; } |
| }; |
| |
| /// RepeatWhileStmt - repeat/while statement. After type-checking, the |
| /// condition is of type Builtin.Int1. |
| class RepeatWhileStmt : public LabeledStmt { |
| SourceLoc RepeatLoc, WhileLoc; |
| Stmt *Body; |
| Expr *Cond; |
| |
| public: |
| RepeatWhileStmt(LabeledStmtInfo LabelInfo, SourceLoc RepeatLoc, Expr *Cond, |
| SourceLoc WhileLoc, Stmt *Body, Optional<bool> implicit = None) |
| : LabeledStmt(StmtKind::RepeatWhile, |
| getDefaultImplicitFlag(implicit, RepeatLoc), |
| LabelInfo), |
| RepeatLoc(RepeatLoc), WhileLoc(WhileLoc), Body(Body), Cond(Cond) {} |
| |
| SourceLoc getStartLoc() const { return getLabelLocOrKeywordLoc(RepeatLoc); } |
| SourceLoc getEndLoc() const; |
| SourceLoc getRepeatLoc() const { return RepeatLoc; } |
| |
| Stmt *getBody() const { return Body; } |
| void setBody(Stmt *s) { Body = s; } |
| |
| Expr *getCond() const { return Cond; } |
| void setCond(Expr *e) { Cond = e; } |
| |
| static bool classof(const Stmt *S) {return S->getKind() == StmtKind::RepeatWhile;} |
| }; |
| |
| /// ForEachStmt - foreach statement that iterates over the elements in a |
| /// container. |
| /// |
| /// Example: |
| /// \code |
| /// for i in 0...10 { |
| /// print(String(i)) |
| /// } |
| /// \endcode |
| class ForEachStmt : public LabeledStmt { |
| SourceLoc ForLoc; |
| Pattern *Pat; |
| SourceLoc InLoc; |
| Expr *Sequence; |
| SourceLoc WhereLoc; |
| Expr *WhereExpr = nullptr; |
| BraceStmt *Body; |
| |
| // Set by Sema: |
| ProtocolConformanceRef sequenceConformance = ProtocolConformanceRef(); |
| VarDecl *iteratorVar = nullptr; |
| Expr *iteratorVarRef = nullptr; |
| OpaqueValueExpr *elementExpr = nullptr; |
| Expr *convertElementExpr = nullptr; |
| |
| public: |
| ForEachStmt(LabeledStmtInfo LabelInfo, SourceLoc ForLoc, Pattern *Pat, |
| SourceLoc InLoc, Expr *Sequence, SourceLoc WhereLoc, |
| Expr *WhereExpr, BraceStmt *Body, Optional<bool> implicit = None) |
| : LabeledStmt(StmtKind::ForEach, getDefaultImplicitFlag(implicit, ForLoc), |
| LabelInfo), |
| ForLoc(ForLoc), Pat(nullptr), InLoc(InLoc), Sequence(Sequence), |
| WhereLoc(WhereLoc), WhereExpr(WhereExpr), Body(Body) { |
| setPattern(Pat); |
| } |
| |
| void setIteratorVar(VarDecl *var) { iteratorVar = var; } |
| VarDecl *getIteratorVar() const { return iteratorVar; } |
| |
| void setIteratorVarRef(Expr *var) { iteratorVarRef = var; } |
| Expr *getIteratorVarRef() const { return iteratorVarRef; } |
| |
| void setElementExpr(OpaqueValueExpr *expr) { elementExpr = expr; } |
| OpaqueValueExpr *getElementExpr() const { return elementExpr; } |
| |
| void setConvertElementExpr(Expr *expr) { convertElementExpr = expr; } |
| Expr *getConvertElementExpr() const { return convertElementExpr; } |
| |
| void setSequenceConformance(ProtocolConformanceRef conformance) { |
| sequenceConformance = conformance; |
| } |
| ProtocolConformanceRef getSequenceConformance() const { |
| return sequenceConformance; |
| } |
| |
| /// getForLoc - Retrieve the location of the 'for' keyword. |
| SourceLoc getForLoc() const { return ForLoc; } |
| |
| /// getInLoc - Retrieve the location of the 'in' keyword. |
| SourceLoc getInLoc() const { return InLoc; } |
| |
| /// getWhereLoc - Retrieve the location of the 'where' keyword. |
| SourceLoc getWhereLoc() const { return WhereLoc; } |
| |
| /// getPattern - Retrieve the pattern describing the iteration variables. |
| /// These variables will only be visible within the body of the loop. |
| Pattern *getPattern() const { return Pat; } |
| void setPattern(Pattern *p); |
| |
| Expr *getWhere() const { return WhereExpr; } |
| void setWhere(Expr *W) { WhereExpr = W; } |
| |
| /// getSequence - Retrieve the Sequence whose elements will be visited |
| /// by this foreach loop, as it was written in the source code and |
| /// subsequently type-checked. To determine the semantic behavior of this |
| /// expression to extract a range, use \c getRangeInit(). |
| Expr *getSequence() const { return Sequence; } |
| void setSequence(Expr *S) { Sequence = S; } |
| |
| /// getBody - Retrieve the body of the loop. |
| BraceStmt *getBody() const { return Body; } |
| void setBody(BraceStmt *B) { Body = B; } |
| |
| SourceLoc getStartLoc() const { return getLabelLocOrKeywordLoc(ForLoc); } |
| SourceLoc getEndLoc() const { return Body->getEndLoc(); } |
| |
| static bool classof(const Stmt *S) { |
| return S->getKind() == StmtKind::ForEach; |
| } |
| }; |
| |
| /// A pattern and an optional guard expression used in a 'case' statement. |
| class CaseLabelItem { |
| enum class Kind { |
| /// A normal pattern |
| Normal = 0, |
| /// `default` |
| Default, |
| }; |
| |
| llvm::PointerIntPair<Pattern *, 1, bool> CasePatternAndResolved; |
| SourceLoc WhereLoc; |
| llvm::PointerIntPair<Expr *, 1, Kind> GuardExprAndKind; |
| |
| CaseLabelItem(Kind kind, Pattern *casePattern, SourceLoc whereLoc, |
| Expr *guardExpr) |
| : CasePatternAndResolved(casePattern, false), WhereLoc(whereLoc), |
| GuardExprAndKind(guardExpr, kind) {} |
| |
| public: |
| CaseLabelItem(const CaseLabelItem &) = default; |
| |
| CaseLabelItem(Pattern *casePattern, SourceLoc whereLoc, Expr *guardExpr) |
| : CaseLabelItem(Kind::Normal, casePattern, whereLoc, guardExpr) {} |
| explicit CaseLabelItem(Pattern *casePattern) |
| : CaseLabelItem(casePattern, SourceLoc(), nullptr) {} |
| |
| static CaseLabelItem getDefault(AnyPattern *pattern, |
| SourceLoc whereLoc, |
| Expr *guardExpr) { |
| assert(pattern); |
| return CaseLabelItem(Kind::Default, reinterpret_cast<Pattern *>(pattern), |
| whereLoc, guardExpr); |
| } |
| static CaseLabelItem getDefault(AnyPattern *pattern) { |
| return getDefault(pattern, SourceLoc(), nullptr); |
| } |
| |
| SourceLoc getWhereLoc() const { return WhereLoc; } |
| |
| SourceLoc getStartLoc() const; |
| SourceLoc getEndLoc() const; |
| SourceRange getSourceRange() const; |
| |
| Pattern *getPattern() { |
| return CasePatternAndResolved.getPointer(); |
| } |
| const Pattern *getPattern() const { |
| return CasePatternAndResolved.getPointer(); |
| } |
| bool isPatternResolved() const { |
| return CasePatternAndResolved.getInt(); |
| } |
| void setPattern(Pattern *CasePattern, bool resolved) { |
| this->CasePatternAndResolved.setPointer(CasePattern); |
| this->CasePatternAndResolved.setInt(resolved); |
| } |
| |
| /// Return the guard expression if present, or null if the case label has |
| /// no guard. |
| Expr *getGuardExpr() { return GuardExprAndKind.getPointer(); } |
| const Expr *getGuardExpr() const { |
| return GuardExprAndKind.getPointer(); |
| } |
| void setGuardExpr(Expr *e) { GuardExprAndKind.setPointer(e); } |
| |
| /// Returns true if this is syntactically a 'default' label. |
| bool isDefault() const { |
| return GuardExprAndKind.getInt() == Kind::Default; |
| } |
| |
| bool isSyntacticallyExhaustive() const; |
| }; |
| |
| /// FallthroughStmt - The keyword "fallthrough". |
| class FallthroughStmt : public Stmt { |
| SourceLoc Loc; |
| CaseStmt *FallthroughSource; |
| CaseStmt *FallthroughDest; |
| |
| public: |
| FallthroughStmt(SourceLoc Loc, Optional<bool> implicit = None) |
| : Stmt(StmtKind::Fallthrough, getDefaultImplicitFlag(implicit, Loc)), |
| Loc(Loc), FallthroughSource(nullptr), FallthroughDest(nullptr) {} |
| |
| SourceLoc getLoc() const { return Loc; } |
| |
| SourceRange getSourceRange() const { return Loc; } |
| |
| /// Get the CaseStmt block from which the fallthrough transfers control. |
| /// Set during Sema. (May stay null if fallthrough is invalid.) |
| CaseStmt *getFallthroughSource() const { return FallthroughSource; } |
| void setFallthroughSource(CaseStmt *C) { |
| assert(!FallthroughSource && "fallthrough source already set?!"); |
| FallthroughSource = C; |
| } |
| |
| /// Get the CaseStmt block to which the fallthrough transfers control. |
| /// Set during Sema. |
| CaseStmt *getFallthroughDest() const { |
| assert(FallthroughDest && "fallthrough dest is not set until Sema"); |
| return FallthroughDest; |
| } |
| void setFallthroughDest(CaseStmt *C) { |
| assert(!FallthroughDest && "fallthrough dest already set?!"); |
| FallthroughDest = C; |
| } |
| |
| static bool classof(const Stmt *S) { |
| return S->getKind() == StmtKind::Fallthrough; |
| } |
| }; |
| |
| enum CaseParentKind { Switch, DoCatch }; |
| |
| /// A 'case' or 'default' block of a switch statement, or a 'catch' clause of a |
| /// do-catch statement. Only valid as the substatement of a SwitchStmt or |
| /// DoCatchStmt. A case block begins either with one or more CaseLabelItems or |
| /// a single 'default' label. |
| /// |
| /// Some examples: |
| /// \code |
| /// case 1: |
| /// case 2, 3: |
| /// case Foo(var x, var y) where x < y: |
| /// case 2 where foo(), 3 where bar(): |
| /// default: |
| /// \endcode |
| /// |
| class CaseStmt final |
| : public Stmt, |
| private llvm::TrailingObjects<CaseStmt, FallthroughStmt *, |
| CaseLabelItem> { |
| friend TrailingObjects; |
| |
| Stmt *ParentStmt = nullptr; |
| SourceLoc UnknownAttrLoc; |
| SourceLoc ItemIntroducerLoc; |
| SourceLoc ItemTerminatorLoc; |
| CaseParentKind ParentKind; |
| |
| llvm::PointerIntPair<BraceStmt *, 1, bool> BodyAndHasFallthrough; |
| |
| Optional<MutableArrayRef<VarDecl *>> CaseBodyVariables; |
| |
| CaseStmt(CaseParentKind ParentKind, SourceLoc ItemIntroducerLoc, |
| ArrayRef<CaseLabelItem> CaseLabelItems, SourceLoc UnknownAttrLoc, |
| SourceLoc ItemTerminatorLoc, BraceStmt *Body, |
| Optional<MutableArrayRef<VarDecl *>> CaseBodyVariables, |
| Optional<bool> Implicit, |
| NullablePtr<FallthroughStmt> fallthroughStmt); |
| |
| public: |
| static CaseStmt * |
| create(ASTContext &C, CaseParentKind ParentKind, SourceLoc ItemIntroducerLoc, |
| ArrayRef<CaseLabelItem> CaseLabelItems, SourceLoc UnknownAttrLoc, |
| SourceLoc ItemTerminatorLoc, BraceStmt *Body, |
| Optional<MutableArrayRef<VarDecl *>> CaseBodyVariables, |
| Optional<bool> Implicit = None, |
| NullablePtr<FallthroughStmt> fallthroughStmt = nullptr); |
| |
| CaseParentKind getParentKind() const { return ParentKind; } |
| |
| Stmt *getParentStmt() const { return ParentStmt; } |
| void setParentStmt(Stmt *S) { |
| assert(S && "Parent statement must be SwitchStmt or DoCatchStmt"); |
| assert((ParentKind == CaseParentKind::Switch && isa<SwitchStmt>(S)) || |
| (ParentKind == CaseParentKind::DoCatch && isa<DoCatchStmt>(S))); |
| ParentStmt = S; |
| } |
| |
| ArrayRef<CaseLabelItem> getCaseLabelItems() const { |
| return {getTrailingObjects<CaseLabelItem>(), Bits.CaseStmt.NumPatterns}; |
| } |
| |
| MutableArrayRef<CaseLabelItem> getMutableCaseLabelItems() { |
| return {getTrailingObjects<CaseLabelItem>(), Bits.CaseStmt.NumPatterns}; |
| } |
| |
| unsigned getNumCaseLabelItems() const { return Bits.CaseStmt.NumPatterns; } |
| |
| NullablePtr<CaseStmt> getFallthroughDest() const { |
| return const_cast<CaseStmt &>(*this).getFallthroughDest(); |
| } |
| |
| NullablePtr<CaseStmt> getFallthroughDest() { |
| if (!hasFallthroughDest()) |
| return nullptr; |
| return (*getTrailingObjects<FallthroughStmt *>())->getFallthroughDest(); |
| } |
| |
| bool hasFallthroughDest() const { return BodyAndHasFallthrough.getInt(); } |
| |
| BraceStmt *getBody() const { return BodyAndHasFallthrough.getPointer(); } |
| void setBody(BraceStmt *body) { BodyAndHasFallthrough.setPointer(body); } |
| |
| /// True if the case block declares any patterns with local variable bindings. |
| bool hasBoundDecls() const { return CaseBodyVariables.hasValue(); } |
| |
| /// Get the source location of the 'case', 'default', or 'catch' of the first |
| /// label. |
| SourceLoc getLoc() const { return ItemIntroducerLoc; } |
| |
| SourceLoc getStartLoc() const { |
| if (UnknownAttrLoc.isValid()) |
| return UnknownAttrLoc; |
| return getLoc(); |
| } |
| SourceLoc getEndLoc() const { return getBody()->getEndLoc(); } |
| |
| SourceRange getLabelItemsRange() const { |
| switch (ParentKind) { |
| case CaseParentKind::Switch: |
| // The range extends from 'case' to the colon at the end. |
| return ItemTerminatorLoc.isValid() |
| ? SourceRange(getLoc(), ItemTerminatorLoc) |
| : getSourceRange(); |
| case CaseParentKind::DoCatch: { |
| // The range extends from 'catch' to the end of the last non-implicit |
| // item. |
| auto items = getCaseLabelItems(); |
| for (auto item = items.rbegin(), end = items.rend(); item != end; |
| ++item) { |
| auto itemEndLoc = item->getEndLoc(); |
| if (itemEndLoc.isValid()) |
| return SourceRange(getLoc(), itemEndLoc); |
| } |
| // Handle the 'catch {' case. |
| return SourceRange(getLoc(), getLoc()); |
| } |
| } |
| llvm_unreachable("invalid parent kind"); |
| } |
| |
| bool isDefault() { return getCaseLabelItems()[0].isDefault(); } |
| |
| bool hasUnknownAttr() const { |
| // Note: This representation doesn't allow for synthesized @unknown cases. |
| // However, that's probably sensible; the purpose of @unknown is for |
| // diagnosing otherwise-non-exhaustive switches, and the user can't edit |
| // a synthesized case. |
| return UnknownAttrLoc.isValid(); |
| } |
| |
| /// Return an ArrayRef containing the case body variables of this CaseStmt. |
| /// |
| /// Asserts if case body variables was not explicitly initialized. In contexts |
| /// where one wants a non-asserting version, \see |
| /// getCaseBodyVariablesOrEmptyArray. |
| ArrayRef<VarDecl *> getCaseBodyVariables() const { |
| ArrayRef<VarDecl *> a = *CaseBodyVariables; |
| return a; |
| } |
| |
| bool hasCaseBodyVariables() const { return CaseBodyVariables.hasValue(); } |
| |
| /// Return an MutableArrayRef containing the case body variables of this |
| /// CaseStmt. |
| /// |
| /// Asserts if case body variables was not explicitly initialized. In contexts |
| /// where one wants a non-asserting version, \see |
| /// getCaseBodyVariablesOrEmptyArray. |
| MutableArrayRef<VarDecl *> getCaseBodyVariables() { |
| return *CaseBodyVariables; |
| } |
| |
| ArrayRef<VarDecl *> getCaseBodyVariablesOrEmptyArray() const { |
| if (!CaseBodyVariables) |
| return ArrayRef<VarDecl *>(); |
| ArrayRef<VarDecl *> a = *CaseBodyVariables; |
| return a; |
| } |
| |
| MutableArrayRef<VarDecl *> getCaseBodyVariablesOrEmptyArray() { |
| if (!CaseBodyVariables) |
| return MutableArrayRef<VarDecl *>(); |
| return *CaseBodyVariables; |
| } |
| |
| /// Find the next case statement within the same 'switch' or 'do-catch', |
| /// if there is one. |
| CaseStmt *findNextCaseStmt() const; |
| |
| static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Case; } |
| |
| size_t numTrailingObjects(OverloadToken<CaseLabelItem>) const { |
| return getNumCaseLabelItems(); |
| } |
| |
| size_t numTrailingObjects(OverloadToken<FallthroughStmt *>) const { |
| return hasFallthroughDest() ? 1 : 0; |
| } |
| }; |
| |
| /// Switch statement. |
| class SwitchStmt final : public LabeledStmt, |
| private llvm::TrailingObjects<SwitchStmt, ASTNode> { |
| friend TrailingObjects; |
| |
| SourceLoc SwitchLoc, LBraceLoc, RBraceLoc; |
| Expr *SubjectExpr; |
| |
| SwitchStmt(LabeledStmtInfo LabelInfo, SourceLoc SwitchLoc, Expr *SubjectExpr, |
| SourceLoc LBraceLoc, unsigned CaseCount, SourceLoc RBraceLoc, |
| Optional<bool> implicit = None) |
| : LabeledStmt(StmtKind::Switch, getDefaultImplicitFlag(implicit, SwitchLoc), |
| LabelInfo), |
| SwitchLoc(SwitchLoc), LBraceLoc(LBraceLoc), RBraceLoc(RBraceLoc), |
| SubjectExpr(SubjectExpr) { |
| Bits.SwitchStmt.CaseCount = CaseCount; |
| } |
| |
| public: |
| /// Allocate a new SwitchStmt in the given ASTContext. |
| static SwitchStmt *create(LabeledStmtInfo LabelInfo, SourceLoc SwitchLoc, |
| Expr *SubjectExpr, |
| SourceLoc LBraceLoc, |
| ArrayRef<ASTNode> Cases, |
| SourceLoc RBraceLoc, |
| ASTContext &C); |
| |
| /// Get the source location of the 'switch' keyword. |
| SourceLoc getSwitchLoc() const { return SwitchLoc; } |
| /// Get the source location of the opening brace. |
| SourceLoc getLBraceLoc() const { return LBraceLoc; } |
| /// Get the source location of the closing brace. |
| SourceLoc getRBraceLoc() const { return RBraceLoc; } |
| |
| SourceLoc getLoc() const { return SwitchLoc; } |
| |
| SourceLoc getStartLoc() const { return getLabelLocOrKeywordLoc(SwitchLoc); } |
| SourceLoc getEndLoc() const { return RBraceLoc; } |
| |
| /// Get the subject expression of the switch. |
| Expr *getSubjectExpr() const { return SubjectExpr; } |
| void setSubjectExpr(Expr *e) { SubjectExpr = e; } |
| |
| ArrayRef<ASTNode> getRawCases() const { |
| return {getTrailingObjects<ASTNode>(), Bits.SwitchStmt.CaseCount}; |
| } |
| |
| private: |
| struct AsCaseStmtWithSkippingNonCaseStmts { |
| AsCaseStmtWithSkippingNonCaseStmts() {} |
| Optional<CaseStmt*> operator()(const ASTNode &N) const { |
| if (auto *CS = llvm::dyn_cast_or_null<CaseStmt>(N.dyn_cast<Stmt*>())) |
| return CS; |
| return None; |
| } |
| }; |
| |
| public: |
| using AsCaseStmtRange = OptionalTransformRange<ArrayRef<ASTNode>, |
| AsCaseStmtWithSkippingNonCaseStmts>; |
| |
| /// Get the list of case clauses. |
| AsCaseStmtRange getCases() const { |
| return AsCaseStmtRange(getRawCases(), AsCaseStmtWithSkippingNonCaseStmts()); |
| } |
| |
| static bool classof(const Stmt *S) { |
| return S->getKind() == StmtKind::Switch; |
| } |
| }; |
| |
| /// DoCatchStmt - do statement with trailing 'catch' clauses. |
| class DoCatchStmt final |
| : public LabeledStmt, |
| private llvm::TrailingObjects<DoCatchStmt, CaseStmt *> { |
| friend TrailingObjects; |
| |
| SourceLoc DoLoc; |
| Stmt *Body; |
| |
| DoCatchStmt(LabeledStmtInfo labelInfo, SourceLoc doLoc, Stmt *body, |
| ArrayRef<CaseStmt *> catches, Optional<bool> implicit) |
| : LabeledStmt(StmtKind::DoCatch, getDefaultImplicitFlag(implicit, doLoc), |
| labelInfo), |
| DoLoc(doLoc), Body(body) { |
| Bits.DoCatchStmt.NumCatches = catches.size(); |
| std::uninitialized_copy(catches.begin(), catches.end(), |
| getTrailingObjects<CaseStmt *>()); |
| for (auto *catchStmt : getCatches()) |
| catchStmt->setParentStmt(this); |
| } |
| |
| public: |
| static DoCatchStmt *create(ASTContext &ctx, LabeledStmtInfo labelInfo, |
| SourceLoc doLoc, Stmt *body, |
| ArrayRef<CaseStmt *> catches, |
| Optional<bool> implicit = None); |
| |
| SourceLoc getDoLoc() const { return DoLoc; } |
| |
| SourceLoc getStartLoc() const { return getLabelLocOrKeywordLoc(DoLoc); } |
| SourceLoc getEndLoc() const { return getCatches().back()->getEndLoc(); } |
| |
| Stmt *getBody() const { return Body; } |
| void setBody(Stmt *s) { Body = s; } |
| |
| ArrayRef<CaseStmt *> getCatches() const { |
| return {getTrailingObjects<CaseStmt *>(), Bits.DoCatchStmt.NumCatches}; |
| } |
| MutableArrayRef<CaseStmt *> getMutableCatches() { |
| return {getTrailingObjects<CaseStmt *>(), Bits.DoCatchStmt.NumCatches}; |
| } |
| |
| /// Does this statement contain a syntactically exhaustive catch |
| /// clause? |
| /// |
| /// Note that an exhaustive do/catch statement can still throw |
| /// errors out of its catch block(s). |
| bool isSyntacticallyExhaustive() const; |
| |
| static bool classof(const Stmt *S) { |
| return S->getKind() == StmtKind::DoCatch; |
| } |
| }; |
| |
| /// BreakStmt - The "break" and "break label" statement. |
| class BreakStmt : public Stmt { |
| SourceLoc Loc; |
| Identifier TargetName; // Named target statement, if specified in the source. |
| SourceLoc TargetLoc; |
| LabeledStmt *Target = nullptr; // Target stmt, wired up by Sema. |
| public: |
| BreakStmt(SourceLoc Loc, Identifier TargetName, SourceLoc TargetLoc, |
| Optional<bool> implicit = None) |
| : Stmt(StmtKind::Break, getDefaultImplicitFlag(implicit, Loc)), Loc(Loc), |
| TargetName(TargetName), TargetLoc(TargetLoc) { |
| } |
| |
| SourceLoc getLoc() const { return Loc; } |
| |
| Identifier getTargetName() const { return TargetName; } |
| void setTargetName(Identifier N) { TargetName = N; } |
| SourceLoc getTargetLoc() const { return TargetLoc; } |
| void setTargetLoc(SourceLoc L) { TargetLoc = L; } |
| |
| // Manipulate the target loop/switch that is bring broken out of. This is set |
| // by sema during type checking. |
| void setTarget(LabeledStmt *LS) { Target = LS; } |
| LabeledStmt *getTarget() const { return Target; } |
| |
| SourceLoc getStartLoc() const { return Loc; } |
| SourceLoc getEndLoc() const { |
| return (TargetLoc.isValid() ? TargetLoc : Loc); |
| } |
| |
| static bool classof(const Stmt *S) { |
| return S->getKind() == StmtKind::Break; |
| } |
| }; |
| |
| /// ContinueStmt - The "continue" and "continue label" statement. |
| class ContinueStmt : public Stmt { |
| SourceLoc Loc; |
| Identifier TargetName; // Named target statement, if specified in the source. |
| SourceLoc TargetLoc; |
| LabeledStmt *Target = nullptr; |
| |
| public: |
| ContinueStmt(SourceLoc Loc, Identifier TargetName, SourceLoc TargetLoc, |
| Optional<bool> implicit = None) |
| : Stmt(StmtKind::Continue, getDefaultImplicitFlag(implicit, Loc)), Loc(Loc), |
| TargetName(TargetName), TargetLoc(TargetLoc) { |
| } |
| |
| Identifier getTargetName() const { return TargetName; } |
| void setTargetName(Identifier N) { TargetName = N; } |
| SourceLoc getTargetLoc() const { return TargetLoc; } |
| void setTargetLoc(SourceLoc L) { TargetLoc = L; } |
| |
| // Manipulate the target loop that is bring continued. This is set by sema |
| // during type checking. |
| void setTarget(LabeledStmt *LS) { Target = LS; } |
| LabeledStmt *getTarget() const { return Target; } |
| |
| SourceLoc getLoc() const { return Loc; } |
| |
| SourceLoc getStartLoc() const { return Loc; } |
| SourceLoc getEndLoc() const { |
| return (TargetLoc.isValid() ? TargetLoc : Loc); |
| } |
| |
| static bool classof(const Stmt *S) { |
| return S->getKind() == StmtKind::Continue; |
| } |
| }; |
| |
| /// FailStmt - A statement that indicates a failable, which is currently |
| /// spelled as "return nil" and can only be used within failable initializers. |
| class FailStmt : public Stmt { |
| SourceLoc ReturnLoc; |
| SourceLoc NilLoc; |
| |
| public: |
| FailStmt(SourceLoc returnLoc, SourceLoc nilLoc, |
| Optional<bool> implicit = None) |
| : Stmt(StmtKind::Fail, getDefaultImplicitFlag(implicit, returnLoc)), |
| ReturnLoc(returnLoc), NilLoc(nilLoc) |
| {} |
| |
| SourceLoc getLoc() const { return ReturnLoc; } |
| |
| SourceRange getSourceRange() const { return SourceRange(ReturnLoc, NilLoc); } |
| |
| static bool classof(const Stmt *S) { |
| return S->getKind() == StmtKind::Fail; |
| } |
| }; |
| |
| /// ThrowStmt - Throws an error. |
| class ThrowStmt : public Stmt { |
| Expr *SubExpr; |
| SourceLoc ThrowLoc; |
| |
| public: |
| explicit ThrowStmt(SourceLoc throwLoc, Expr *subExpr) |
| : Stmt(StmtKind::Throw, /*Implicit=*/false), |
| SubExpr(subExpr), ThrowLoc(throwLoc) {} |
| |
| SourceLoc getThrowLoc() const { return ThrowLoc; } |
| |
| SourceLoc getStartLoc() const { return ThrowLoc; } |
| SourceLoc getEndLoc() const; |
| SourceRange getSourceRange() const { |
| return SourceRange(ThrowLoc, getEndLoc()); |
| } |
| |
| Expr *getSubExpr() const { return SubExpr; } |
| void setSubExpr(Expr *subExpr) { SubExpr = subExpr; } |
| |
| static bool classof(const Stmt *S) { |
| return S->getKind() == StmtKind::Throw; |
| } |
| }; |
| |
| /// PoundAssertStmt - Asserts that a condition is true, at compile time. |
| class PoundAssertStmt : public Stmt { |
| SourceRange Range; |
| Expr *Condition; |
| StringRef Message; |
| |
| public: |
| PoundAssertStmt(SourceRange Range, Expr *condition, StringRef message) |
| : Stmt(StmtKind::PoundAssert, /*Implicit=*/false), |
| Range(Range), |
| Condition(condition), |
| Message(message) {} |
| |
| SourceRange getSourceRange() const { return Range; } |
| |
| Expr *getCondition() const { return Condition; } |
| StringRef getMessage() const { return Message; } |
| |
| void setCondition(Expr *condition) { Condition = condition; } |
| |
| static bool classof(const Stmt *S) { |
| return S->getKind() == StmtKind::PoundAssert; |
| } |
| }; |
| |
| inline void simple_display(llvm::raw_ostream &out, Stmt *S) { |
| if (S) |
| out << Stmt::getKindName(S->getKind()); |
| else |
| out << "(null)"; |
| }; |
| |
| } // end namespace swift |
| |
| #endif // SWIFT_AST_STMT_H |