diff --git a/lib/Sema/CSClosure.cpp b/lib/Sema/CSClosure.cpp index 42373fffe9d8f..6e1a3035a0c08 100644 --- a/lib/Sema/CSClosure.cpp +++ b/lib/Sema/CSClosure.cpp @@ -1409,7 +1409,15 @@ class SyntacticElementSolutionApplication } auto caseStmt = cast(rawCase.get()); - visitCaseStmt(caseStmt); + // Body of the `case` statement can contain a `fallthrough` + // statement that requires both source and destination + // `case` preambles to be type-checked, so bodies of `case` + // statements should be visited after preambles. + visitCaseStmtPreamble(caseStmt); + } + + for (auto *caseStmt : switchStmt->getCases()) { + visitCaseStmtBody(caseStmt); // Check restrictions on '@unknown'. if (caseStmt->hasUnknownAttr()) { @@ -1436,7 +1444,7 @@ class SyntacticElementSolutionApplication return doStmt; } - ASTNode visitCaseStmt(CaseStmt *caseStmt) { + void visitCaseStmtPreamble(CaseStmt *caseStmt) { // Translate the patterns and guard expressions for each case label item. for (auto &caseItem : caseStmt->getMutableCaseLabelItems()) { SolutionApplicationTarget caseTarget(&caseItem, @@ -1453,11 +1461,16 @@ class SyntacticElementSolutionApplication solution.getType(prev)->mapTypeOutOfContext()); expected->setInterfaceType(type); } + } - // Translate the body. + void visitCaseStmtBody(CaseStmt *caseStmt) { auto *newBody = visit(caseStmt->getBody()).get(); caseStmt->setBody(cast(newBody)); + } + ASTNode visitCaseStmt(CaseStmt *caseStmt) { + visitCaseStmtPreamble(caseStmt); + visitCaseStmtBody(caseStmt); return caseStmt; } diff --git a/test/expr/closure/multi_statement.swift b/test/expr/closure/multi_statement.swift index 1b9f25761c68e..90bf7b58bce65 100644 --- a/test/expr/closure/multi_statement.swift +++ b/test/expr/closure/multi_statement.swift @@ -404,3 +404,23 @@ func test_type_finder_doesnt_walk_into_inner_closures() { return x } } + +// rdar://93796211 (issue#59035) - crash during solution application to fallthrough statement +func test_fallthrough_stmt() { + { + var collector: [Void] = [] + for _: Void in [] { + switch (() as Void?, ()) { + case (let a?, let b): + // expected-warning@-1 {{constant 'b' inferred to have type '()', which may be unexpected}} + // expected-note@-2 {{add an explicit type annotation to silence this warning}} + collector.append(a) + fallthrough + case (nil, let b): + // expected-warning@-1 {{constant 'b' inferred to have type '()', which may be unexpected}} + // expected-note@-2 {{add an explicit type annotation to silence this warning}} + collector.append(b) + } + } + }() +}