Skip to content

[requires-evolution] Conditionally compiled catch clauses #27905

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 29 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
25e1a3d
Update DoCatchStmt to use CaseStmt internally instead of CatchStmt
owenv Oct 12, 2019
f74f414
update AST to reflect DoCatchStmt changes
owenv Oct 12, 2019
180adaa
Parse multi-pattern catches
owenv Oct 13, 2019
c9a0cc9
Update typechecking for do-catch statements
owenv Oct 13, 2019
ad4d509
Update typechecking for do-catch statements
owenv Oct 13, 2019
85ffeec
Hack together SILGen for multi-pattern catches
owenv Oct 13, 2019
5dd919f
bug fixes
owenv Oct 13, 2019
16b3145
working on catchstmt libsyntax changes
owenv Oct 14, 2019
d8934f5
revert parsing hacks
owenv Oct 15, 2019
b728a36
Reimplement multi-pattern catch parsing in a less hacky way, and made…
owenv Oct 16, 2019
631f22e
fix a libSyntax bug with catches that don't have a pattern, update th…
owenv Oct 16, 2019
9cc9ba9
fix indenting for switches and catches
owenv Oct 16, 2019
f8ef72d
tweak catch code completion
owenv Oct 16, 2019
e6f3f14
Update profiling for catch statements
owenv Oct 16, 2019
f655de2
Refactor CaseStmt a bit
owenv Oct 17, 2019
9bc8e96
Cleanup catch SILGen and begin expanding test coverage
owenv Oct 17, 2019
2890124
Improve do-catch pattern matching interpreter test coverage
owenv Oct 18, 2019
0c74a7b
update some comments
owenv Oct 18, 2019
9b9f2e2
Fix catch clause code completion
owenv Oct 21, 2019
eb5afae
rebase and remove use of deprecated API
owenv Oct 27, 2019
853d243
use separate syntax nodes for catch- and case- items in order to avoi…
owenv Oct 27, 2019
8bac563
Refactor catch clause formatting
owenv Oct 30, 2019
f667a26
Clean up handling of CaseStmt in SILProfiler
owenv Oct 30, 2019
e64f96c
Stop using removed TypeChecker API
owenv Nov 6, 2019
5c2c4a7
More updates for changed typechecker api
owenv Nov 11, 2019
b1aa6b8
adopt new syntax nodes for catch items
owenv Jan 7, 2020
bb5c515
update AST to reflect DoCatchStmt changes
owenv Oct 12, 2019
2752e4e
Add support for IfConfigDecl as a child of DoCatchStmt in the AST
owenv Oct 27, 2019
fe64516
Add support for parsing #if directives surrounding catch clauses
owenv Oct 28, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 0 additions & 23 deletions include/swift/AST/ASTScope.h
Original file line number Diff line number Diff line change
Expand Up @@ -1858,29 +1858,6 @@ class ForEachPatternScope final : public ASTScopeImpl {
DeclConsumer) const override;
};

class CatchStmtScope final : public AbstractStmtScope {
public:
CatchStmt *const stmt;
CatchStmtScope(CatchStmt *e) : stmt(e) {}
virtual ~CatchStmtScope() {}

protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;

private:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);

public:
std::string getClassName() const override;
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
Stmt *getStmt() const override { return stmt; }

protected:
bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
ASTScopeImpl::DeclConsumer) const override;
};

class CaseStmtScope final : public AbstractStmtScope {
public:
CaseStmt *const stmt;
Expand Down
2 changes: 0 additions & 2 deletions include/swift/AST/NameLookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -587,8 +587,6 @@ class FindLocalVal : public StmtVisitor<FindLocalVal> {
void visitCaseStmt(CaseStmt *S);

void visitDoCatchStmt(DoCatchStmt *S);
void visitCatchClauses(ArrayRef<CatchStmt*> clauses);
void visitCatchStmt(CatchStmt *S);

};

Expand Down
219 changes: 95 additions & 124 deletions include/swift/AST/Stmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -538,105 +538,6 @@ class DoStmt : public LabeledStmt {
static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Do; }
};

/// An individual 'catch' clause.
///
/// This isn't really an independent statement any more than CaseStmt
/// is; it's just a structural part of a DoCatchStmt.
class CatchStmt : public Stmt {
SourceLoc CatchLoc;
SourceLoc WhereLoc;
Pattern *ErrorPattern;
Expr *GuardExpr;
Stmt *CatchBody;

public:
CatchStmt(SourceLoc catchLoc, Pattern *errorPattern,
SourceLoc whereLoc, Expr *guardExpr, Stmt *body,
Optional<bool> implicit = None)
: Stmt(StmtKind::Catch, getDefaultImplicitFlag(implicit, catchLoc)),
CatchLoc(catchLoc), WhereLoc(whereLoc),
ErrorPattern(nullptr), GuardExpr(guardExpr), CatchBody(body) {
setErrorPattern(errorPattern);
}

SourceLoc getCatchLoc() const { return CatchLoc; }

/// The location of the 'where' keyword if there's a guard expression.
SourceLoc getWhereLoc() const { return WhereLoc; }

SourceLoc getStartLoc() const { return CatchLoc; }
SourceLoc getEndLoc() const { return CatchBody->getEndLoc(); }

Stmt *getBody() const { return CatchBody; }
void setBody(Stmt *body) { CatchBody = body; }

Pattern *getErrorPattern() { return ErrorPattern; }
const Pattern *getErrorPattern() const { return ErrorPattern; }
void setErrorPattern(Pattern *pattern);

/// Is this catch clause "syntactically exhaustive"?
bool isSyntacticallyExhaustive() const;

/// Return the guard expression if present, or null if the catch has
/// no guard.
Expr *getGuardExpr() const { return GuardExpr; }
void setGuardExpr(Expr *guard) { GuardExpr = guard; }

static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Catch; }
};

/// DoCatchStmt - do statement with trailing 'catch' clauses.
class DoCatchStmt final : public LabeledStmt,
private llvm::TrailingObjects<DoCatchStmt, CatchStmt *> {
friend TrailingObjects;

SourceLoc DoLoc;
Stmt *Body;

DoCatchStmt(LabeledStmtInfo labelInfo, SourceLoc doLoc,
Stmt *body, ArrayRef<CatchStmt*> 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<CatchStmt *>());
}

public:
static DoCatchStmt *create(ASTContext &ctx, LabeledStmtInfo labelInfo,
SourceLoc doLoc, Stmt *body,
ArrayRef<CatchStmt*> 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<CatchStmt*> getCatches() const {
return {getTrailingObjects<CatchStmt*>(), Bits.DoCatchStmt.NumCatches};
}
MutableArrayRef<CatchStmt*> getMutableCatches() {
return {getTrailingObjects<CatchStmt*>(), 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;
}
};


/// 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>;
Expand Down Expand Up @@ -935,6 +836,8 @@ class CaseLabelItem {
bool isDefault() const {
return GuardExprAndKind.getInt() == Kind::Default;
}

bool isSyntacticallyExhaustive() const;
};

/// FallthroughStmt - The keyword "fallthrough".
Expand Down Expand Up @@ -976,9 +879,12 @@ class FallthroughStmt : public Stmt {
}
};

/// A 'case' or 'default' block of a switch statement. Only valid as the
/// substatement of a SwitchStmt. A case block begins either with one or more
/// CaseLabelItems or a single 'default' label.
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
Expand All @@ -996,28 +902,32 @@ class CaseStmt final
friend TrailingObjects;

SourceLoc UnknownAttrLoc;
SourceLoc CaseLoc;
SourceLoc ColonLoc;
SourceLoc ItemIntroducerLoc;
SourceLoc ItemTerminatorLoc;
CaseParentKind ParentKind;

llvm::PointerIntPair<Stmt *, 1, bool> BodyAndHasFallthrough;

Optional<MutableArrayRef<VarDecl *>> CaseBodyVariables;

CaseStmt(SourceLoc CaseLoc, ArrayRef<CaseLabelItem> CaseLabelItems,
SourceLoc UnknownAttrLoc, SourceLoc ColonLoc, Stmt *Body,
CaseStmt(CaseParentKind ParentKind, SourceLoc ItemIntroducerLoc,
ArrayRef<CaseLabelItem> CaseLabelItems, SourceLoc UnknownAttrLoc,
SourceLoc ItemTerminatorLoc, Stmt *Body,
Optional<MutableArrayRef<VarDecl *>> CaseBodyVariables,
Optional<bool> Implicit,
NullablePtr<FallthroughStmt> fallthroughStmt);

public:
static CaseStmt *
create(ASTContext &C, SourceLoc CaseLoc,
create(ASTContext &C, CaseParentKind ParentKind, SourceLoc ItemIntroducerLoc,
ArrayRef<CaseLabelItem> CaseLabelItems, SourceLoc UnknownAttrLoc,
SourceLoc ColonLoc, Stmt *Body,
SourceLoc ItemTerminatorLoc, Stmt *Body,
Optional<MutableArrayRef<VarDecl *>> CaseBodyVariables,
Optional<bool> Implicit = None,
NullablePtr<FallthroughStmt> fallthroughStmt = nullptr);

CaseParentKind getParentKind() const { return ParentKind; }

ArrayRef<CaseLabelItem> getCaseLabelItems() const {
return {getTrailingObjects<CaseLabelItem>(), Bits.CaseStmt.NumPatterns};
}
Expand Down Expand Up @@ -1046,8 +956,9 @@ class CaseStmt final
/// 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' or 'default' of the first label.
SourceLoc getLoc() const { return CaseLoc; }
/// 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())
Expand All @@ -1056,7 +967,9 @@ class CaseStmt final
}
SourceLoc getEndLoc() const { return getBody()->getEndLoc(); }
SourceRange getLabelItemsRange() const {
return ColonLoc.isValid() ? SourceRange(getLoc(), ColonLoc) : getSourceRange();
return ItemTerminatorLoc.isValid()
? SourceRange(getLoc(), ItemTerminatorLoc)
: getSourceRange();
}

bool isDefault() { return getCaseLabelItems()[0].isDefault(); }
Expand Down Expand Up @@ -1115,6 +1028,20 @@ class CaseStmt final
}
};

/// Helper used by SwitchStmt and DoCatchStmt to support #if
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;
}
};

using AsCaseStmtRange =
OptionalTransformRange<ArrayRef<ASTNode>,
AsCaseStmtWithSkippingNonCaseStmts>;

/// Switch statement.
class SwitchStmt final : public LabeledStmt,
private llvm::TrailingObjects<SwitchStmt, ASTNode> {
Expand Down Expand Up @@ -1162,20 +1089,7 @@ class SwitchStmt final : public LabeledStmt,
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());
Expand All @@ -1186,6 +1100,63 @@ class SwitchStmt final : public LabeledStmt,
}
};

/// DoCatchStmt - do statement with trailing 'catch' clauses.
class DoCatchStmt final : public LabeledStmt,
private llvm::TrailingObjects<DoCatchStmt, ASTNode> {
friend TrailingObjects;

SourceLoc DoLoc;
Stmt *Body;

DoCatchStmt(LabeledStmtInfo labelInfo, SourceLoc doLoc, Stmt *body,
ArrayRef<ASTNode> 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<ASTNode>());
}

public:
static DoCatchStmt *create(ASTContext &ctx, LabeledStmtInfo labelInfo,
SourceLoc doLoc, Stmt *body,
ArrayRef<ASTNode> catches,
Optional<bool> implicit = None);

SourceLoc getDoLoc() const { return DoLoc; }

SourceLoc getStartLoc() const { return getLabelLocOrKeywordLoc(DoLoc); }
SourceLoc getEndLoc() const { return getRawCatches().back().getEndLoc(); }

Stmt *getBody() const { return Body; }
void setBody(Stmt *s) { Body = s; }

ArrayRef<ASTNode> getRawCatches() const {
return {getTrailingObjects<ASTNode>(), Bits.DoCatchStmt.NumCatches};
}

MutableArrayRef<ASTNode> getMutableRawCatches() {
return {getTrailingObjects<ASTNode>(), Bits.DoCatchStmt.NumCatches};
}

/// Get the list of catch clauses.
AsCaseStmtRange getCatches() const {
return AsCaseStmtRange(getRawCatches(),
AsCaseStmtWithSkippingNonCaseStmts());
}

/// 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;
Expand Down
1 change: 0 additions & 1 deletion include/swift/AST/StmtNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ ABSTRACT_STMT(Labeled, Stmt)
LABELED_STMT(Switch, LabeledStmt)
STMT_RANGE(Labeled, If, Switch)
STMT(Case, Stmt)
STMT(Catch, Stmt)
STMT(Break, Stmt)
STMT(Continue, Stmt)
STMT(Fallthrough, Stmt)
Expand Down
4 changes: 3 additions & 1 deletion include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1603,7 +1603,9 @@ class Parser {
ParserResult<Stmt> parseStmtWhile(LabeledStmtInfo LabelInfo);
ParserResult<Stmt> parseStmtRepeat(LabeledStmtInfo LabelInfo);
ParserResult<Stmt> parseStmtDo(LabeledStmtInfo LabelInfo);
ParserResult<CatchStmt> parseStmtCatch();
ParserStatus parseStmtCatches(SmallVectorImpl<ASTNode> &catches,
bool isActive, bool &sawCatchKeyword);
ParserResult<CaseStmt> parseStmtCatch(bool IsActive);
ParserResult<Stmt> parseStmtForEach(LabeledStmtInfo LabelInfo);
ParserResult<Stmt> parseStmtSwitch(LabeledStmtInfo LabelInfo);
ParserStatus parseStmtCases(SmallVectorImpl<ASTNode> &cases, bool IsActive);
Expand Down
22 changes: 6 additions & 16 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1716,24 +1716,14 @@ class PrintStmt : public StmtVisitor<PrintStmt> {
printRec(S->getBody());
OS << '\n';
Indent += 2;
visitCatches(S->getCatches());
Indent -= 2;
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}
void visitCatches(ArrayRef<CatchStmt*> clauses) {
for (auto clause : clauses) {
visitCatchStmt(clause);
}
}
void visitCatchStmt(CatchStmt *clause) {
printCommon(clause, "catch") << '\n';
printRec(clause->getErrorPattern());
if (auto guard = clause->getGuardExpr()) {
for (auto N : S->getRawCatches()) {
OS << '\n';
printRec(guard);
if (N.is<Stmt *>())
printRec(N.get<Stmt *>());
else
printRec(N.get<Decl *>());
}
OS << '\n';
printRec(clause->getBody());
Indent -= 2;
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}
};
Expand Down
Loading