Skip to content

Commit 8237ea4

Browse files
committed
xxx
1 parent 43b6117 commit 8237ea4

16 files changed

+149
-27
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1228,6 +1228,9 @@ ERROR(single_value_stmt_must_be_unlabeled,none,
12281228
ERROR(if_expr_must_be_syntactically_exhaustive,none,
12291229
"'if' must have an unconditional 'else' to be used as expression",
12301230
())
1231+
ERROR(do_catch_expr_must_be_syntactically_exhaustive,none,
1232+
"'do catch' must have an unconditional 'catch' to be used as expression",
1233+
())
12311234
ERROR(single_value_stmt_branch_empty,none,
12321235
"expected expression in branch of '%0' expression",
12331236
(StmtKind))

include/swift/AST/Expr.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6116,7 +6116,7 @@ class KeyPathDotExpr : public Expr {
61166116
class SingleValueStmtExpr : public Expr {
61176117
public:
61186118
enum class Kind {
6119-
If, Switch
6119+
If, Switch, Do, DoCatch
61206120
};
61216121

61226122
private:

include/swift/AST/Stmt.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1418,6 +1418,9 @@ class DoCatchStmt final
14181418
return {getTrailingObjects<CaseStmt *>(), Bits.DoCatchStmt.NumCatches};
14191419
}
14201420

1421+
/// Retrieve the complete set of branches for this do-catch statement.
1422+
ArrayRef<Stmt *> getBranches(SmallVectorImpl<Stmt *> &scratch) const;
1423+
14211424
/// Does this statement contain a syntactically exhaustive catch
14221425
/// clause?
14231426
///

include/swift/AST/TypeCheckRequests.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3901,6 +3901,10 @@ class IsSingleValueStmtResult {
39013901
/// The statement is an 'if' statement without an unconditional 'else'.
39023902
NonExhaustiveIf,
39033903

3904+
/// The statement is a 'do catch' statement without an unconditional
3905+
/// 'catch'.
3906+
NonExhaustiveDoCatch,
3907+
39043908
/// There is no branch that produces a resulting value.
39053909
NoResult,
39063910

@@ -3957,6 +3961,9 @@ class IsSingleValueStmtResult {
39573961
static IsSingleValueStmtResult nonExhaustiveIf() {
39583962
return IsSingleValueStmtResult(Kind::NonExhaustiveIf);
39593963
}
3964+
static IsSingleValueStmtResult nonExhaustiveDoCatch() {
3965+
return IsSingleValueStmtResult(Kind::NonExhaustiveDoCatch);
3966+
}
39603967
static IsSingleValueStmtResult noResult() {
39613968
return IsSingleValueStmtResult(Kind::NoResult);
39623969
}

lib/AST/ASTVerifier.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,6 +1222,7 @@ class Verifier : public ASTWalker {
12221222
break;
12231223
case Kind::UnterminatedBranches:
12241224
case Kind::NonExhaustiveIf:
1225+
case Kind::NonExhaustiveDoCatch:
12251226
case Kind::UnhandledStmt:
12261227
case Kind::CircularReference:
12271228
case Kind::HasLabel:

lib/AST/Expr.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2494,12 +2494,15 @@ SingleValueStmtExpr *SingleValueStmtExpr::createWithWrappedBranches(
24942494

24952495
if (auto *S = BS->getSingleActiveStatement()) {
24962496
if (mustBeExpr) {
2497-
// If this must be an expression, we can eagerly wrap any exhaustive if
2498-
// and switch branch.
2497+
// If this must be an expression, we can eagerly wrap any exhaustive if,
2498+
// switch, and do statement.
24992499
if (auto *IS = dyn_cast<IfStmt>(S)) {
25002500
if (!IS->isSyntacticallyExhaustive())
25012501
continue;
2502-
} else if (!isa<SwitchStmt>(S)) {
2502+
} else if (auto *DCS = dyn_cast<DoCatchStmt>(S)) {
2503+
if (!DCS->isSyntacticallyExhaustive())
2504+
continue;
2505+
} else if (!isa<SwitchStmt>(S) && !isa<DoStmt>(S)) {
25032506
continue;
25042507
}
25052508
} else {
@@ -2582,18 +2585,28 @@ SingleValueStmtExpr::Kind SingleValueStmtExpr::getStmtKind() const {
25822585
return Kind::If;
25832586
case StmtKind::Switch:
25842587
return Kind::Switch;
2588+
case StmtKind::Do:
2589+
return Kind::Do;
2590+
case StmtKind::DoCatch:
2591+
return Kind::DoCatch;
25852592
default:
25862593
llvm_unreachable("Unhandled kind!");
25872594
}
25882595
}
25892596

25902597
ArrayRef<Stmt *>
25912598
SingleValueStmtExpr::getBranches(SmallVectorImpl<Stmt *> &scratch) const {
2599+
assert(scratch.empty());
25922600
switch (getStmtKind()) {
25932601
case Kind::If:
25942602
return cast<IfStmt>(getStmt())->getBranches(scratch);
25952603
case Kind::Switch:
25962604
return cast<SwitchStmt>(getStmt())->getBranches(scratch);
2605+
case Kind::Do:
2606+
scratch.push_back(cast<DoStmt>(getStmt())->getBody());
2607+
return scratch;
2608+
case Kind::DoCatch:
2609+
return cast<DoCatchStmt>(getStmt())->getBranches(scratch);
25972610
}
25982611
llvm_unreachable("Unhandled case in switch!");
25992612
}

lib/AST/Stmt.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,15 @@ SwitchStmt::getBranches(SmallVectorImpl<Stmt *> &scratch) const {
854854
return scratch;
855855
}
856856

857+
ArrayRef<Stmt *>
858+
DoCatchStmt::getBranches(SmallVectorImpl<Stmt *> &scratch) const {
859+
assert(scratch.empty());
860+
scratch.push_back(getBody());
861+
for (auto *CS : getCatches())
862+
scratch.push_back(CS->getBody());
863+
return scratch;
864+
}
865+
857866
// See swift/Basic/Statistic.h for declaration: this enables tracing Stmts, is
858867
// defined here to avoid too much layering violation / circular linkage
859868
// dependency.

lib/Basic/LangOptions.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ using namespace swift;
3333
LangOptions::LangOptions() {
3434
// Note: Introduce default-on language options here.
3535
#ifndef NDEBUG
36-
Features.insert(Feature::ParserRoundTrip);
37-
Features.insert(Feature::ParserValidation);
36+
// Features.insert(Feature::ParserRoundTrip);
37+
// Features.insert(Feature::ParserValidation);
3838
#endif
3939
}
4040

lib/Parse/ParseExpr.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -584,11 +584,11 @@ ParserResult<Expr> Parser::parseExprUnary(Diag<> Message, bool isExprBasic) {
584584
// First check to see if we have the start of a regex literal `/.../`.
585585
tryLexRegexLiteral(/*forUnappliedOperator*/ false);
586586

587-
// Try parse an 'if' or 'switch' as an expression. Note we do this here in
588-
// parseExprUnary as we don't allow postfix syntax to hang off such
587+
// Try parse 'if', 'switch', and 'do' as expressions. Note we do this here
588+
// in parseExprUnary as we don't allow postfix syntax to hang off such
589589
// expressions to avoid ambiguities such as postfix '.member', which can
590590
// currently be parsed as a static dot member for a result builder.
591-
if (Tok.isAny(tok::kw_if, tok::kw_switch)) {
591+
if (Tok.isAny(tok::kw_if, tok::kw_switch, tok::kw_do)) {
592592
auto Result = parseStmt();
593593
Expr *E = nullptr;
594594
if (Result.isNonNull()) {

lib/Parse/ParseStmt.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ bool Parser::isStartOfStmt(bool preferExpr) {
7878
// "try" cannot actually start any statements, but we parse it there for
7979
// better recovery in cases like 'try return'.
8080

81-
// For 'if' and 'switch' we can parse as an expression.
82-
if (peekToken().isAny(tok::kw_if, tok::kw_switch)) {
81+
// For 'if', 'switch', and 'do' we can parse as an expression.
82+
if (peekToken().isAny(tok::kw_if, tok::kw_switch, tok::kw_do)) {
8383
return false;
8484
}
8585
Parser::BacktrackingScope backtrack(*this);
@@ -157,7 +157,8 @@ ParserStatus Parser::parseExprOrStmt(ASTNode &Result) {
157157
// We could also achieve this by more eagerly attempting to parse an 'if'
158158
// or 'switch' as an expression when in statement position, but that
159159
// could result in less useful recovery behavior.
160-
if ((isa<IfStmt>(S) || isa<SwitchStmt>(S)) && Tok.is(tok::kw_as)) {
160+
if ((isa<IfStmt>(S) || isa<SwitchStmt>(S) || isa<DoStmt>(S) ||
161+
isa<DoCatchStmt>(S)) && Tok.is(tok::kw_as)) {
161162
auto *SVE = SingleValueStmtExpr::createWithWrappedBranches(
162163
Context, S, CurDeclContext, /*mustBeExpr*/ true);
163164
auto As = parseExprAs();
@@ -778,8 +779,8 @@ ParserResult<Stmt> Parser::parseStmtReturn(SourceLoc tryLoc) {
778779
tok::pound_else, tok::pound_elseif)) {
779780
return false;
780781
}
781-
// Allowed for if/switch expressions.
782-
if (Tok.isAny(tok::kw_if, tok::kw_switch)) {
782+
// Allowed for if/switch/do expressions.
783+
if (Tok.isAny(tok::kw_if, tok::kw_switch, tok::kw_do)) {
783784
return true;
784785
}
785786
if (isStartOfStmt(/*preferExpr*/ true) || isStartOfSwiftDecl())

lib/Sema/CSSyntacticElement.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -999,14 +999,23 @@ class SyntacticElementConstraintGenerator
999999

10001000
SmallVector<ElementInfo, 4> elements;
10011001

1002-
// First, let's record a body of `do` statement.
1003-
elements.push_back(makeElement(doStmt->getBody(), doLoc));
1002+
// First, let's record a body of `do` statement. Note we need to add a
1003+
// SyntaticElement locator path element here to avoid treating the inner
1004+
// brace conjunction as being isolated if 'doLoc' is for an isolated
1005+
// conjunction (as is the case with 'do' expressions).
1006+
auto *doBodyLoc = cs.getConstraintLocator(
1007+
doLoc, LocatorPathElt::SyntacticElement(doStmt->getBody()));
1008+
elements.push_back(makeElement(doStmt->getBody(), doBodyLoc));
10041009

10051010
// After that has been type-checked, let's switch to
10061011
// individual `catch` statements.
10071012
for (auto *catchStmt : doStmt->getCatches())
10081013
elements.push_back(makeElement(catchStmt, doLoc));
10091014

1015+
// Inject a join if we have one.
1016+
if (auto *join = context.ElementJoin.getPtrOrNull())
1017+
elements.push_back(makeJoinElement(cs, join, locator));
1018+
10101019
createConjunction(elements, doLoc);
10111020
}
10121021

@@ -1195,6 +1204,10 @@ class SyntacticElementConstraintGenerator
11951204
contextInfo.value_or(ContextualTypeInfo()), isDiscarded));
11961205
}
11971206

1207+
// Inject a join if we have one.
1208+
if (auto *join = context.ElementJoin.getPtrOrNull())
1209+
elements.push_back(makeJoinElement(cs, join, locator));
1210+
11981211
createConjunction(elements, locator);
11991212
}
12001213

lib/Sema/ConstraintLocator.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,8 @@ bool ConstraintLocator::isForSingleValueStmtConjunction() const {
661661
}
662662

663663
bool ConstraintLocator::isForSingleValueStmtConjunctionOrBrace() const {
664-
if (!isExpr<SingleValueStmtExpr>(getAnchor()))
664+
auto *SVE = getAsExpr<SingleValueStmtExpr>(getAnchor());
665+
if (!SVE)
665666
return false;
666667

667668
auto path = getPath();
@@ -672,11 +673,17 @@ bool ConstraintLocator::isForSingleValueStmtConjunctionOrBrace() const {
672673
continue;
673674
}
674675

675-
// Ignore a SyntaticElement path element for a case statement of a switch.
676+
// Ignore a SyntaticElement path element for a case statement of a switch,
677+
// or the catch of a do-catch, or the brace of a do-statement.
676678
if (auto elt = path.back().getAs<LocatorPathElt::SyntacticElement>()) {
677679
if (elt->getElement().isStmt(StmtKind::Case)) {
678680
path = path.drop_back();
679-
continue;
681+
break;
682+
}
683+
if (elt->getElement().isStmt(StmtKind::Brace) &&
684+
isa<DoCatchStmt>(SVE->getStmt())) {
685+
path = path.drop_back();
686+
break;
680687
}
681688
}
682689
break;

lib/Sema/MiscDiagnostics.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3947,6 +3947,11 @@ class SingleValueStmtUsageChecker final : public ASTWalker {
39473947
diag::if_expr_must_be_syntactically_exhaustive);
39483948
break;
39493949
}
3950+
case IsSingleValueStmtResult::Kind::NonExhaustiveDoCatch: {
3951+
Diags.diagnose(S->getStartLoc(),
3952+
diag::do_catch_expr_must_be_syntactically_exhaustive);
3953+
break;
3954+
}
39503955
case IsSingleValueStmtResult::Kind::HasLabel: {
39513956
// FIXME: We should offer a fix-it to remove (currently we don't track
39523957
// the colon SourceLoc).

lib/Sema/TypeCheckStmt.cpp

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2997,14 +2997,11 @@ areBranchesValidForSingleValueStmt(Evaluator &eval, ArrayRef<Stmt *> branches) {
29972997

29982998
IsSingleValueStmtResult
29992999
IsSingleValueStmtRequest::evaluate(Evaluator &eval, const Stmt *S) const {
3000-
if (!isa<IfStmt>(S) && !isa<SwitchStmt>(S))
3001-
return IsSingleValueStmtResult::unhandledStmt();
3002-
30033000
// Statements must be unlabeled.
3004-
auto *LS = cast<LabeledStmt>(S);
3005-
if (LS->getLabelInfo())
3006-
return IsSingleValueStmtResult::hasLabel();
3007-
3001+
if (auto *LS = dyn_cast<LabeledStmt>(S)) {
3002+
if (LS->getLabelInfo())
3003+
return IsSingleValueStmtResult::hasLabel();
3004+
}
30083005
if (auto *IS = dyn_cast<IfStmt>(S)) {
30093006
// Must be exhaustive.
30103007
if (!IS->isSyntacticallyExhaustive())
@@ -3017,7 +3014,17 @@ IsSingleValueStmtRequest::evaluate(Evaluator &eval, const Stmt *S) const {
30173014
SmallVector<Stmt *, 4> scratch;
30183015
return areBranchesValidForSingleValueStmt(eval, SS->getBranches(scratch));
30193016
}
3020-
llvm_unreachable("Unhandled case");
3017+
if (auto *DS = dyn_cast<DoStmt>(S))
3018+
return areBranchesValidForSingleValueStmt(eval, DS->getBody());
3019+
3020+
if (auto *DCS = dyn_cast<DoCatchStmt>(S)) {
3021+
if (!DCS->isSyntacticallyExhaustive())
3022+
return IsSingleValueStmtResult::nonExhaustiveDoCatch();
3023+
3024+
SmallVector<Stmt *, 4> scratch;
3025+
return areBranchesValidForSingleValueStmt(eval, DCS->getBranches(scratch));
3026+
}
3027+
return IsSingleValueStmtResult::unhandledStmt();
30213028
}
30223029

30233030
void swift::checkUnknownAttrRestrictions(

test/SILGen/do_expr.swift

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// RUN: %target-swift-emit-silgen -enable-experimental-feature ThenStatements %s | %FileCheck %s
2+
// RUN: %target-swift-emit-ir -enable-experimental-feature ThenStatements %s
3+
4+
@discardableResult
5+
func throwsError(_ x: Int = 0) throws -> Int { 0 }
6+
7+
func test1() -> Int {
8+
do { 5 }
9+
}
10+
11+
func test2() -> Int {
12+
return do { 5 }
13+
}
14+
15+
func test3() -> Int {
16+
let x = do { 5 }
17+
return x
18+
}
19+
20+
func test4() -> Int {
21+
do { then 5 }
22+
}
23+
24+
func test5() -> Int {
25+
let x = do { (); then 5 }
26+
return x
27+
}
28+
29+
func test6(_ x: Bool) -> Int {
30+
let x = do {
31+
let y = 0
32+
try throwsError()
33+
then y
34+
} catch {
35+
7
36+
}
37+
return x
38+
}
39+
40+
func test7() throws -> Int {
41+
let x = do {
42+
let y = 0
43+
then try throwsError(y)
44+
} catch _ where .random() {
45+
then try throwsError()
46+
} catch {
47+
8
48+
}
49+
return x
50+
}
51+
52+
// CHECK: test1

test/expr/unary/if_expr.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,7 @@ func continue1() -> Int {
933933
func return1() -> Int {
934934
// Make sure we always reject a return.
935935
let i = if .random() {
936+
()
936937
do {
937938
for _ in [0] {
938939
while true {

0 commit comments

Comments
 (0)