Skip to content

Commit c72f9e5

Browse files
committed
[Parse] Adjust diagnostics for effects specifiers in closure signature
1 parent 1c791d3 commit c72f9e5

File tree

6 files changed

+48
-37
lines changed

6 files changed

+48
-37
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -749,8 +749,7 @@ ERROR(async_after_throws,none,
749749
"'async' must precede %select{'throws'|'rethrows'}0", (bool))
750750
ERROR(async_init,none, "initializer cannot be marked 'async'", ())
751751
ERROR(duplicate_effect_specifier,none,
752-
"unexpected %select{'throws'|'rethrows'|'async'}0",
753-
(unsigned))
752+
"unexpected '%0' specifier", (StringRef))
754753

755754
// Enum Types
756755
ERROR(expected_expr_enum_case_raw_value,PointsToFirstBadToken,

lib/Parse/ParseExpr.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2374,6 +2374,8 @@ ParserStatus Parser::parseClosureSignatureIfPresent(
23742374
if (consumeIf(tok::arrow)) {
23752375
if (!canParseType())
23762376
return makeParserSuccess();
2377+
2378+
consumeEffectsSpecifiers();
23772379
}
23782380
}
23792381

@@ -2396,6 +2398,8 @@ ParserStatus Parser::parseClosureSignatureIfPresent(
23962398
if (consumeIf(tok::arrow)) {
23972399
if (!canParseType())
23982400
return makeParserSuccess();
2401+
2402+
consumeEffectsSpecifiers();
23992403
}
24002404
}
24012405

@@ -2606,6 +2610,10 @@ ParserStatus Parser::parseClosureSignatureIfPresent(
26062610
status.setIsParseError();
26072611
} else {
26082612
explicitResultType = new (Context) TypeExpr(explicitResultTypeRepr);
2613+
2614+
// Check for 'throws' and 'rethrows' after the type and correct it.
2615+
parseEffectsSpecifiers(arrowLoc, asyncLoc, throwsLoc,
2616+
/*rethrows*/nullptr);
26092617
}
26102618
}
26112619
}

lib/Parse/ParsePattern.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -848,7 +848,7 @@ ParserStatus Parser::parseEffectsSpecifiers(SourceLoc existingArrowLoc,
848848
Tok.isContextualKeyword("async")) {
849849

850850
if (asyncLoc.isValid()) {
851-
diagnose(Tok, diag::duplicate_effect_specifier, 2)
851+
diagnose(Tok, diag::duplicate_effect_specifier, Tok.getText())
852852
.fixItRemove(Tok.getLoc());
853853
} else if (existingArrowLoc.isValid()) {
854854
SourceLoc insertLoc = existingArrowLoc;
@@ -876,18 +876,17 @@ ParserStatus Parser::parseEffectsSpecifiers(SourceLoc existingArrowLoc,
876876
(Tok.isAny(tok::kw_throw, tok::kw_try) && !Tok.isAtStartOfLine())) {
877877
bool isRethrows = Tok.is(tok::kw_rethrows);
878878

879-
if (Tok.isAny(tok::kw_throw, tok::kw_try)) {
879+
if (throwsLoc.isValid()) {
880+
diagnose(Tok, diag::duplicate_effect_specifier, Tok.getText())
881+
.fixItRemove(Tok.getLoc());
882+
} else if (Tok.isAny(tok::kw_throw, tok::kw_try)) {
880883
// Replace 'throw' or 'try' with 'throws'.
881884
diagnose(Tok, diag::throw_in_function_type)
882885
.fixItReplace(Tok.getLoc(), "throws");
883886
} else if (!rethrows && isRethrows) {
884887
// Replace 'rethrows' with 'throws' unless it's allowed.
885888
diagnose(Tok, diag::rethrowing_function_type)
886889
.fixItReplace(Tok.getLoc(), "throws");
887-
} else if (throwsLoc.isValid()) {
888-
diagnose(Tok, diag::duplicate_effect_specifier,
889-
rethrows ? (isRethrows ? 1 : 0) : 0)
890-
.fixItRemove(Tok.getLoc());
891890
} else if (existingArrowLoc.isValid()) {
892891
diagnose(Tok, diag::async_or_throws_in_wrong_position,
893892
rethrows ? (isRethrows ? 1 : 0) : 0)

lib/Parse/ParseType.cpp

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,39 +1462,18 @@ bool Parser::canParseType() {
14621462
break;
14631463
}
14641464

1465-
// Handle type-function if we have an 'async'.
1466-
if (shouldParseExperimentalConcurrency() &&
1467-
Tok.isContextualKeyword("async")) {
1468-
consumeToken();
1469-
1470-
// 'async' isn't a valid type without being followed by throws/rethrows
1471-
// or a return.
1472-
if (!Tok.isAny(tok::kw_throws, tok::kw_rethrows, tok::arrow))
1473-
return false;
1474-
}
1465+
if (!isAtFunctionTypeArrow())
1466+
return true;
14751467

1476-
// Handle type-function if we have an arrow or 'throws'/'rethrows' modifier.
1477-
if (Tok.isAny(tok::kw_throws, tok::kw_rethrows)) {
1468+
// Handle type-function if we have an '->' with optional
1469+
// 'async' and/or 'throws'.
1470+
while (isEffectsSpecifier(Tok))
14781471
consumeToken();
14791472

1480-
// Allow 'async' here even though it is ill-formed, so we can provide
1481-
// a better error.
1482-
if (shouldParseExperimentalConcurrency() &&
1483-
Tok.isContextualKeyword("async"))
1484-
consumeToken();
1485-
1486-
// "throws" or "rethrows" isn't a valid type without being followed by
1487-
// a return. We also accept 'async' here so we can provide a better
1488-
// error.
1489-
if (!Tok.is(tok::arrow))
1490-
return false;
1491-
}
1473+
if (!consumeIf(tok::arrow))
1474+
return false;
14921475

1493-
if (consumeIf(tok::arrow)) {
1494-
return canParseType();
1495-
}
1496-
1497-
return true;
1476+
return canParseType();
14981477
}
14991478

15001479
bool Parser::canParseTypeIdentifierOrTypeComposition() {

test/Parse/async.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ func asyncGlobal6() -> Int throws async { }
2222

2323
func asyncGlobal7() throws -> Int async { } // expected-error{{'async' may only occur before '->'}}{{35-41=}}{{21-21=async }}
2424

25+
func asyncGlobal8() async throws async -> async Int async {}
26+
// expected-error@-1{{unexpected 'async' specifier}} {{34-40=}}
27+
// expected-error@-2{{unexpected 'async' specifier}} {{43-49=}}
28+
// expected-error@-3{{unexpected 'async' specifier}} {{53-59=}}
29+
2530
class X {
2631
init() async { } // expected-error{{initializer cannot be marked 'async'}}
2732

test/Parse/errors.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,27 @@ func postRethrows2(_ f: () throws -> Int) -> rethrows Int { // expected-error{{'
116116
return try f()
117117
}
118118

119+
func postThrows3() {
120+
_ = { () -> Int throws in } // expected-error {{'throws' may only occur before '->'}} {{19-26=}} {{12-12=throws }}
121+
}
122+
123+
func dupThrows1() throws rethrows -> throws Int throw {}
124+
// expected-error@-1 {{unexpected 'rethrows' specifier}} {{26-35=}}
125+
// expected-error@-2 {{unexpected 'throws' specifier}} {{38-45=}}
126+
// expected-error@-3 {{unexpected 'throw' specifier}} {{49-55=}}
127+
128+
func dupThrows2(_ f: () throws -> rethrows Int) {}
129+
// expected-error@-1 {{unexpected 'rethrows' specifier}} {{35-44=}}
130+
131+
func dupThrows3() {
132+
_ = { () try throws in }
133+
// expected-error@-1 {{expected throwing specifier; did you mean 'throws'?}} {{12-15=throws}}
134+
// expected-error@-2 {{unexpected 'throws' specifier}} {{16-23=}}
135+
136+
_ = { () throws -> Int throws in }
137+
// expected-error@-1 {{unexpected 'throws' specifier}} {{26-33=}}
138+
}
139+
119140
func incompleteThrowType() {
120141
// FIXME: Bad recovery for incomplete function type.
121142
let _: () throws

0 commit comments

Comments
 (0)