Skip to content

Commit 840ed6a

Browse files
authored
Merge pull request #75891 from hamishknight/fellthrough
[Sema] Improve handling of `fallthrough` in `if`/`switch` expressions
2 parents b104bed + ea8f801 commit 840ed6a

22 files changed

+423
-128
lines changed

include/swift/AST/ASTBridging.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1491,10 +1491,10 @@ BridgedDoCatchStmt BridgedDoCatchStmt_createParsed(
14911491
BridgedNullableTypeRepr cThrownType, BridgedStmt cBody,
14921492
BridgedArrayRef cCatches);
14931493

1494-
SWIFT_NAME("BridgedFallthroughStmt.createParsed(_:loc:)")
1494+
SWIFT_NAME("BridgedFallthroughStmt.createParsed(loc:declContext:)")
14951495
BridgedFallthroughStmt
1496-
BridgedFallthroughStmt_createParsed(BridgedASTContext cContext,
1497-
BridgedSourceLoc cLoc);
1496+
BridgedFallthroughStmt_createParsed(BridgedSourceLoc cLoc,
1497+
BridgedDeclContext cDC);
14981498

14991499
SWIFT_NAME("BridgedForEachStmt.createParsed(_:labelInfo:forLoc:tryLoc:awaitLoc:"
15001500
"pattern:inLoc:sequence:whereLoc:whereExpr:body:)")

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,10 +1329,11 @@ ERROR(single_value_stmt_branch_empty,none,
13291329
"expected expression in branch of '%0' expression",
13301330
(StmtKind))
13311331
ERROR(single_value_stmt_branch_must_end_in_result,none,
1332-
"non-expression branch of '%0' expression may only end with a 'throw'",
1333-
(StmtKind))
1332+
"non-expression branch of '%0' expression may only end with a 'throw'"
1333+
"%select{| or 'fallthrough'}1",
1334+
(StmtKind, bool))
13341335
ERROR(cannot_jump_in_single_value_stmt,none,
1335-
"cannot '%0' in '%1' when used as expression",
1336+
"cannot use '%0' to transfer control out of '%1' expression",
13361337
(StmtKind, StmtKind))
13371338
WARNING(effect_marker_on_single_value_stmt,none,
13381339
"'%0' has no effect on '%1' expression", (StringRef, StmtKind))

include/swift/AST/Stmt.h

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,36 +1159,29 @@ class alignas(1 << PatternAlignInBits) CaseLabelItem {
11591159
/// FallthroughStmt - The keyword "fallthrough".
11601160
class FallthroughStmt : public Stmt {
11611161
SourceLoc Loc;
1162-
CaseStmt *FallthroughSource;
1163-
CaseStmt *FallthroughDest;
1162+
DeclContext *DC;
11641163

1165-
public:
1166-
FallthroughStmt(SourceLoc Loc, std::optional<bool> implicit = std::nullopt)
1164+
FallthroughStmt(SourceLoc Loc, DeclContext *DC,
1165+
std::optional<bool> implicit = std::nullopt)
11671166
: Stmt(StmtKind::Fallthrough, getDefaultImplicitFlag(implicit, Loc)),
1168-
Loc(Loc), FallthroughSource(nullptr), FallthroughDest(nullptr) {}
1167+
Loc(Loc), DC(DC) {}
1168+
public:
1169+
static FallthroughStmt *createParsed(SourceLoc Loc, DeclContext *DC);
11691170

11701171
SourceLoc getLoc() const { return Loc; }
11711172

11721173
SourceRange getSourceRange() const { return Loc; }
11731174

1175+
DeclContext *getDeclContext() const { return DC; }
1176+
void setDeclContext(DeclContext *newDC) { DC = newDC; }
1177+
11741178
/// Get the CaseStmt block from which the fallthrough transfers control.
1175-
/// Set during Sema. (May stay null if fallthrough is invalid.)
1176-
CaseStmt *getFallthroughSource() const { return FallthroughSource; }
1177-
void setFallthroughSource(CaseStmt *C) {
1178-
assert(!FallthroughSource && "fallthrough source already set?!");
1179-
FallthroughSource = C;
1180-
}
1179+
/// Returns \c nullptr if the fallthrough is invalid.
1180+
CaseStmt *getFallthroughSource() const;
11811181

11821182
/// Get the CaseStmt block to which the fallthrough transfers control.
1183-
/// Set during Sema.
1184-
CaseStmt *getFallthroughDest() const {
1185-
assert(FallthroughDest && "fallthrough dest is not set until Sema");
1186-
return FallthroughDest;
1187-
}
1188-
void setFallthroughDest(CaseStmt *C) {
1189-
assert(!FallthroughDest && "fallthrough dest already set?!");
1190-
FallthroughDest = C;
1191-
}
1183+
/// Returns \c nullptr if the fallthrough is invalid.
1184+
CaseStmt *getFallthroughDest() const;
11921185

11931186
static bool classof(const Stmt *S) {
11941187
return S->getKind() == StmtKind::Fallthrough;
@@ -1613,6 +1606,7 @@ class BreakStmt : public Stmt {
16131606
}
16141607

16151608
DeclContext *getDeclContext() const { return DC; }
1609+
void setDeclContext(DeclContext *newDC) { DC = newDC; }
16161610

16171611
static bool classof(const Stmt *S) {
16181612
return S->getKind() == StmtKind::Break;
@@ -1648,6 +1642,7 @@ class ContinueStmt : public Stmt {
16481642
}
16491643

16501644
DeclContext *getDeclContext() const { return DC; }
1645+
void setDeclContext(DeclContext *newDC) { DC = newDC; }
16511646

16521647
static bool classof(const Stmt *S) {
16531648
return S->getKind() == StmtKind::Continue;

include/swift/AST/TypeCheckRequests.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4162,6 +4162,29 @@ class ContinueTargetRequest
41624162
bool isCached() const { return true; }
41634163
};
41644164

4165+
struct FallthroughSourceAndDest {
4166+
CaseStmt *Source;
4167+
CaseStmt *Dest;
4168+
};
4169+
4170+
/// Lookup the source and destination of a 'fallthrough'.
4171+
class FallthroughSourceAndDestRequest
4172+
: public SimpleRequest<FallthroughSourceAndDestRequest,
4173+
FallthroughSourceAndDest(const FallthroughStmt *),
4174+
RequestFlags::Cached> {
4175+
public:
4176+
using SimpleRequest::SimpleRequest;
4177+
4178+
private:
4179+
friend SimpleRequest;
4180+
4181+
FallthroughSourceAndDest evaluate(Evaluator &evaluator,
4182+
const FallthroughStmt *FS) const;
4183+
4184+
public:
4185+
bool isCached() const { return true; }
4186+
};
4187+
41654188
/// Precheck a ReturnStmt, which involves some initial validation, as well as
41664189
/// applying a conversion to a FailStmt if needed.
41674190
class PreCheckReturnStmtRequest

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,9 @@ SWIFT_REQUEST(TypeChecker, BreakTargetRequest,
482482
SWIFT_REQUEST(TypeChecker, ContinueTargetRequest,
483483
LabeledStmt *(const ContinueStmt *),
484484
Cached, NoLocationInfo)
485+
SWIFT_REQUEST(TypeChecker, FallthroughSourceAndDestRequest,
486+
FallthroughSourceAndDest(const FallthroughStmt *),
487+
Cached, NoLocationInfo)
485488
SWIFT_REQUEST(TypeChecker, PreCheckReturnStmtRequest,
486489
Stmt *(ReturnStmt *, DeclContext *),
487490
Cached, NoLocationInfo)

lib/AST/ASTBridging.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2005,9 +2005,9 @@ BridgedDoCatchStmt BridgedDoCatchStmt_createParsed(
20052005
}
20062006

20072007
BridgedFallthroughStmt
2008-
BridgedFallthroughStmt_createParsed(BridgedASTContext cContext,
2009-
BridgedSourceLoc cLoc) {
2010-
return new (cContext.unbridged()) FallthroughStmt(cLoc.unbridged());
2008+
BridgedFallthroughStmt_createParsed(BridgedSourceLoc cLoc,
2009+
BridgedDeclContext cDC) {
2010+
return FallthroughStmt::createParsed(cLoc.unbridged(), cDC.unbridged());
20112011
}
20122012

20132013
BridgedForEachStmt BridgedForEachStmt_createParsed(

lib/AST/Stmt.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,23 @@ LabeledStmt *ContinueStmt::getTarget() const {
989989
return evaluateOrDefault(eval, ContinueTargetRequest{this}, nullptr);
990990
}
991991

992+
FallthroughStmt *FallthroughStmt::createParsed(SourceLoc Loc, DeclContext *DC) {
993+
auto &ctx = DC->getASTContext();
994+
return new (ctx) FallthroughStmt(Loc, DC);
995+
}
996+
997+
CaseStmt *FallthroughStmt::getFallthroughSource() const {
998+
auto &eval = getDeclContext()->getASTContext().evaluator;
999+
return evaluateOrDefault(eval, FallthroughSourceAndDestRequest{this}, {})
1000+
.Source;
1001+
}
1002+
1003+
CaseStmt *FallthroughStmt::getFallthroughDest() const {
1004+
auto &eval = getDeclContext()->getASTContext().evaluator;
1005+
return evaluateOrDefault(eval, FallthroughSourceAndDestRequest{this}, {})
1006+
.Dest;
1007+
}
1008+
9921009
SourceLoc swift::extractNearestSourceLoc(const Stmt *S) {
9931010
return S->getStartLoc();
9941011
}

lib/ASTGen/Sources/ASTGen/Stmts.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,8 @@ extension ASTGenVisitor {
339339

340340
func generate(fallThroughStmt node: FallThroughStmtSyntax) -> BridgedFallthroughStmt {
341341
return .createParsed(
342-
self.ctx,
343-
loc: self.generateSourceLoc(node.fallthroughKeyword)
342+
loc: self.generateSourceLoc(node.fallthroughKeyword),
343+
declContext: self.declContext
344344
)
345345
}
346346

lib/Parse/ParseStmt.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -648,8 +648,8 @@ ParserResult<Stmt> Parser::parseStmt(bool fromASTGen) {
648648
if (LabelInfo) diagnose(LabelInfo.Loc, diag::invalid_label_on_stmt);
649649
if (tryLoc.isValid()) diagnose(tryLoc, diag::try_on_stmt, Tok.getText());
650650

651-
return makeParserResult(
652-
new (Context) FallthroughStmt(consumeToken(tok::kw_fallthrough)));
651+
auto loc = consumeToken(tok::kw_fallthrough);
652+
return makeParserResult(FallthroughStmt::createParsed(loc, CurDeclContext));
653653
}
654654
case tok::pound_assert:
655655
if (LabelInfo) diagnose(LabelInfo.Loc, diag::invalid_label_on_stmt);

lib/Sema/CSSyntacticElement.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1794,7 +1794,7 @@ class SyntacticElementSolutionApplication
17941794
}
17951795

17961796
ASTNode visitFallthroughStmt(FallthroughStmt *fallthroughStmt) {
1797-
if (checkFallthroughStmt(context.getAsDeclContext(), fallthroughStmt))
1797+
if (checkFallthroughStmt(fallthroughStmt))
17981798
hadError = true;
17991799
return fallthroughStmt;
18001800
}

lib/Sema/MiscDiagnostics.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4478,7 +4478,7 @@ class SingleValueStmtUsageChecker final : public ASTWalker {
44784478
// default.
44794479
Diags.diagnose(branch->getEndLoc(),
44804480
diag::single_value_stmt_branch_must_end_in_result,
4481-
S->getKind());
4481+
S->getKind(), isa<SwitchStmt>(S));
44824482
}
44834483
break;
44844484
}

0 commit comments

Comments
 (0)