Skip to content

[SE-0276] Support multiple patterns in catch clauses #27776

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

Merged
merged 1 commit into from
Apr 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -1893,29 +1893,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 @@ -593,8 +593,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
205 changes: 94 additions & 111 deletions include/swift/AST/Stmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -559,105 +559,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 @@ -962,6 +863,8 @@ class CaseLabelItem {
bool isDefault() const {
return GuardExprAndKind.getInt() == Kind::Default;
}

bool isSyntacticallyExhaustive() const;
};

/// FallthroughStmt - The keyword "fallthrough".
Expand Down Expand Up @@ -1003,9 +906,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 @@ -1023,28 +929,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 @@ -1073,17 +983,38 @@ 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())
return UnknownAttrLoc;
return getLoc();
}
SourceLoc getEndLoc() const { return getBody()->getEndLoc(); }

SourceRange getLabelItemsRange() const {
return ColonLoc.isValid() ? SourceRange(getLoc(), ColonLoc) : getSourceRange();
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());
}
}
}

bool isDefault() { return getCaseLabelItems()[0].isDefault(); }
Expand Down Expand Up @@ -1213,6 +1144,58 @@ class SwitchStmt final : public LabeledStmt,
}
};

/// 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 *>());
}

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;
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
2 changes: 1 addition & 1 deletion include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1617,7 +1617,7 @@ class Parser {
ParserResult<Stmt> parseStmtRepeat(LabeledStmtInfo LabelInfo);
ParserResult<Stmt> parseStmtDo(LabeledStmtInfo LabelInfo,
bool shouldSkipDoTokenConsume = false);
ParserResult<CatchStmt> parseStmtCatch();
ParserResult<CaseStmt> parseStmtCatch();
ParserResult<Stmt> parseStmtForEach(LabeledStmtInfo LabelInfo);
ParserResult<Stmt> parseStmtSwitch(LabeledStmtInfo LabelInfo);
ParserStatus parseStmtCases(SmallVectorImpl<ASTNode> &cases, bool IsActive);
Expand Down
15 changes: 2 additions & 13 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1710,22 +1710,11 @@ class PrintStmt : public StmtVisitor<PrintStmt> {
Indent -= 2;
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}
void visitCatches(ArrayRef<CatchStmt*> clauses) {
void visitCatches(ArrayRef<CaseStmt *> clauses) {
for (auto clause : clauses) {
visitCatchStmt(clause);
visitCaseStmt(clause);
}
}
void visitCatchStmt(CatchStmt *clause) {
printCommon(clause, "catch") << '\n';
printRec(clause->getErrorPattern());
if (auto guard = clause->getGuardExpr()) {
OS << '\n';
printRec(guard);
}
OS << '\n';
printRec(clause->getBody());
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}
};

} // end anonymous namespace
Expand Down
14 changes: 1 addition & 13 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3364,22 +3364,10 @@ void PrintAST::visitDoCatchStmt(DoCatchStmt *stmt) {
Printer << tok::kw_do << " ";
visit(stmt->getBody());
for (auto clause : stmt->getCatches()) {
visitCatchStmt(clause);
visitCaseStmt(clause);
}
}

void PrintAST::visitCatchStmt(CatchStmt *stmt) {
Printer << tok::kw_catch << " ";
printPattern(stmt->getErrorPattern());
if (auto guard = stmt->getGuardExpr()) {
Printer << " " << tok::kw_where << " ";
// FIXME: print guard expression
(void) guard;
}
Printer << ' ';
visit(stmt->getBody());
}

void PrintAST::visitForEachStmt(ForEachStmt *stmt) {
Printer << tok::kw_for << " ";
printPattern(stmt->getPattern());
Expand Down
1 change: 0 additions & 1 deletion lib/AST/ASTScope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,6 @@ DEFINE_GET_CLASS_NAME(DoCatchStmtScope)
DEFINE_GET_CLASS_NAME(SwitchStmtScope)
DEFINE_GET_CLASS_NAME(ForEachStmtScope)
DEFINE_GET_CLASS_NAME(ForEachPatternScope)
DEFINE_GET_CLASS_NAME(CatchStmtScope)
DEFINE_GET_CLASS_NAME(CaseStmtScope)
DEFINE_GET_CLASS_NAME(BraceStmtScope)

Expand Down
Loading