Skip to content

Commit 162648d

Browse files
author
Harlan
authored
Add fixit for '-> throws' to 'throws ->' (#3335)
1 parent 32c5595 commit 162648d

File tree

4 files changed

+49
-24
lines changed

4 files changed

+49
-24
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -604,9 +604,9 @@ ERROR(generic_non_function,PointsToFirstBadToken,
604604
"only syntactic function types can be generic", ())
605605
ERROR(rethrowing_function_type,PointsToFirstBadToken,
606606
"only function declarations may be marked 'rethrows'", ())
607-
ERROR(throws_after_function_result,none,
607+
ERROR(throws_in_wrong_position,none,
608608
"'throws' may only occur before '->'", ())
609-
ERROR(rethrows_after_function_result,none,
609+
ERROR(rethrows_in_wrong_position,none,
610610
"'rethrows' may only occur before '->'", ())
611611
ERROR(throw_in_function_type,none,
612612
"expected throwing specifier; did you mean 'throws'?", ())

lib/Parse/ParseExpr.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,13 +186,13 @@ ParserResult<Expr> Parser::parseExprArrow() {
186186
if (Tok.is(tok::kw_throws)) {
187187
throwsLoc = consumeToken(tok::kw_throws);
188188
if (!Tok.is(tok::arrow)) {
189-
diagnose(throwsLoc, diag::throws_after_function_result);
189+
diagnose(throwsLoc, diag::throws_in_wrong_position);
190190
return nullptr;
191191
}
192192
}
193193
arrowLoc = consumeToken(tok::arrow);
194194
if (Tok.is(tok::kw_throws)) {
195-
diagnose(Tok.getLoc(), diag::throws_after_function_result);
195+
diagnose(Tok.getLoc(), diag::throws_in_wrong_position);
196196
throwsLoc = consumeToken(tok::kw_throws);
197197
}
198198
auto arrow = new (Context) ArrowExpr(throwsLoc, arrowLoc);

lib/Parse/ParsePattern.cpp

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,26 @@ Parser::parseFunctionSignature(Identifier SimpleName,
648648
}
649649

650650
SourceLoc arrowLoc;
651+
652+
auto diagnoseInvalidThrows = [&]() -> Optional<InFlightDiagnostic> {
653+
if (throwsLoc.isValid())
654+
return None;
655+
656+
if (Tok.is(tok::kw_throws)) {
657+
throwsLoc = consumeToken();
658+
} else if (Tok.is(tok::kw_rethrows)) {
659+
throwsLoc = consumeToken();
660+
rethrows = true;
661+
}
662+
663+
if (!throwsLoc.isValid())
664+
return None;
665+
666+
auto diag = rethrows ? diag::rethrows_in_wrong_position
667+
: diag::throws_in_wrong_position;
668+
return diagnose(Tok, diag);
669+
};
670+
651671
// If there's a trailing arrow, parse the rest as the result type.
652672
if (Tok.isAny(tok::arrow, tok::colon)) {
653673
if (!consumeIf(tok::arrow, arrowLoc)) {
@@ -657,6 +677,15 @@ Parser::parseFunctionSignature(Identifier SimpleName,
657677
arrowLoc = consumeToken(tok::colon);
658678
}
659679

680+
// Check for 'throws' and 'rethrows' after the arrow, but
681+
// before the type, and correct it.
682+
if (auto diagOpt = diagnoseInvalidThrows()) {
683+
assert(arrowLoc.isValid());
684+
assert(throwsLoc.isValid());
685+
(*diagOpt).fixItExchange(SourceRange(arrowLoc),
686+
SourceRange(throwsLoc));
687+
}
688+
660689
ParserResult<TypeRepr> ResultType =
661690
parseType(diag::expected_type_function_result);
662691
if (ResultType.hasCodeCompletion())
@@ -672,26 +701,14 @@ Parser::parseFunctionSignature(Identifier SimpleName,
672701
}
673702

674703
// Check for 'throws' and 'rethrows' after the type and correct it.
675-
if (!throwsLoc.isValid()) {
676-
if (Tok.is(tok::kw_throws)) {
677-
throwsLoc = consumeToken();
678-
} else if (Tok.is(tok::kw_rethrows)) {
679-
throwsLoc = consumeToken();
680-
rethrows = true;
681-
}
682-
683-
if (throwsLoc.isValid()) {
684-
assert(arrowLoc.isValid());
685-
assert(retType);
686-
auto diag = rethrows ? diag::rethrows_after_function_result
687-
: diag::throws_after_function_result;
688-
SourceLoc typeEndLoc = Lexer::getLocForEndOfToken(SourceMgr,
689-
retType->getEndLoc());
690-
SourceLoc throwsEndLoc = Lexer::getLocForEndOfToken(SourceMgr, throwsLoc);
691-
diagnose(Tok, diag)
692-
.fixItInsert(arrowLoc, rethrows ? "rethrows " : "throws ")
693-
.fixItRemoveChars(typeEndLoc, throwsEndLoc);
694-
}
704+
if (auto diagOpt = diagnoseInvalidThrows()) {
705+
assert(arrowLoc.isValid());
706+
assert(retType);
707+
SourceLoc typeEndLoc = Lexer::getLocForEndOfToken(SourceMgr,
708+
retType->getEndLoc());
709+
SourceLoc throwsEndLoc = Lexer::getLocForEndOfToken(SourceMgr, throwsLoc);
710+
(*diagOpt).fixItInsert(arrowLoc, rethrows ? "rethrows " : "throws ")
711+
.fixItRemoveChars(typeEndLoc, throwsEndLoc);
695712
}
696713

697714
return Status;

test/Parse/errors.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,18 @@ func postThrows() -> Int throws { // expected-error{{'throws' may only occur bef
110110
return 5
111111
}
112112

113+
func postThrows2() -> throws Int { // expected-error{{'throws' may only occur before '->'}}{{20-22=throws}}{{23-29=->}}
114+
return try postThrows()
115+
}
116+
113117
func postRethrows(_ f: () throws -> Int) -> Int rethrows { // expected-error{{'rethrows' may only occur before '->'}}{{42-42=rethrows }}{{48-57=}}
114118
return try f()
115119
}
116120

121+
func postRethrows2(_ f: () throws -> Int) -> rethrows Int { // expected-error{{'rethrows' may only occur before '->'}}{{43-45=rethrows}}{{46-54=->}}
122+
return try f()
123+
}
124+
117125
// rdar://21328447
118126
func fixitThrow0() throw {} // expected-error{{expected throwing specifier; did you mean 'throws'?}} {{20-25=throws}}
119127
func fixitThrow1() throw -> Int {} // expected-error{{expected throwing specifier; did you mean 'throws'?}} {{20-25=throws}}

0 commit comments

Comments
 (0)