Skip to content

Commit 4e9992c

Browse files
committed
[CSClosure] Fix crash in fallthrough statement checking
`fallthrough` requires both source and destination `case` "preambles" be type-checked before it could be validated, which means that solution application for `case` statements in a `switch` has to be split in two - preamble first and bodies afterwards. Resolves: #59035 Resolves: rdar://93796211
1 parent 54102ef commit 4e9992c

File tree

2 files changed

+36
-3
lines changed

2 files changed

+36
-3
lines changed

lib/Sema/CSClosure.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1409,7 +1409,15 @@ class SyntacticElementSolutionApplication
14091409
}
14101410

14111411
auto caseStmt = cast<CaseStmt>(rawCase.get<Stmt *>());
1412-
visitCaseStmt(caseStmt);
1412+
// Body of the `case` statement can contain a `fallthrough`
1413+
// statement that requires both source and destination
1414+
// `case` preambles to be type-checked, so bodies of `case`
1415+
// statements should be visited after preambles.
1416+
visitCaseStmtPreamble(caseStmt);
1417+
}
1418+
1419+
for (auto *caseStmt : switchStmt->getCases()) {
1420+
visitCaseStmtBody(caseStmt);
14131421

14141422
// Check restrictions on '@unknown'.
14151423
if (caseStmt->hasUnknownAttr()) {
@@ -1436,7 +1444,7 @@ class SyntacticElementSolutionApplication
14361444
return doStmt;
14371445
}
14381446

1439-
ASTNode visitCaseStmt(CaseStmt *caseStmt) {
1447+
void visitCaseStmtPreamble(CaseStmt *caseStmt) {
14401448
// Translate the patterns and guard expressions for each case label item.
14411449
for (auto &caseItem : caseStmt->getMutableCaseLabelItems()) {
14421450
SolutionApplicationTarget caseTarget(&caseItem,
@@ -1453,11 +1461,16 @@ class SyntacticElementSolutionApplication
14531461
solution.getType(prev)->mapTypeOutOfContext());
14541462
expected->setInterfaceType(type);
14551463
}
1464+
}
14561465

1457-
// Translate the body.
1466+
void visitCaseStmtBody(CaseStmt *caseStmt) {
14581467
auto *newBody = visit(caseStmt->getBody()).get<Stmt *>();
14591468
caseStmt->setBody(cast<BraceStmt>(newBody));
1469+
}
14601470

1471+
ASTNode visitCaseStmt(CaseStmt *caseStmt) {
1472+
visitCaseStmtPreamble(caseStmt);
1473+
visitCaseStmtBody(caseStmt);
14611474
return caseStmt;
14621475
}
14631476

test/expr/closure/multi_statement.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,3 +404,23 @@ func test_type_finder_doesnt_walk_into_inner_closures() {
404404
return x
405405
}
406406
}
407+
408+
// rdar://93796211 (issue#59035) - crash during solution application to fallthrough statement
409+
func test_fallthrough_stmt() {
410+
{
411+
var collector: [Void] = []
412+
for _: Void in [] {
413+
switch (() as Void?, ()) {
414+
case (let a?, let b):
415+
// expected-warning@-1 {{constant 'b' inferred to have type '()', which may be unexpected}}
416+
// expected-note@-2 {{add an explicit type annotation to silence this warning}}
417+
collector.append(a)
418+
fallthrough
419+
case (nil, let b):
420+
// expected-warning@-1 {{constant 'b' inferred to have type '()', which may be unexpected}}
421+
// expected-note@-2 {{add an explicit type annotation to silence this warning}}
422+
collector.append(b)
423+
}
424+
}
425+
}()
426+
}

0 commit comments

Comments
 (0)