Skip to content

Commit 48ef1ad

Browse files
authored
Merge pull request #5721 from rintaro/parse-functy
[Parse] Minor code improvement in function-type parsing
2 parents 688a94d + 2a2da1f commit 48ef1ad

File tree

5 files changed

+36
-43
lines changed

5 files changed

+36
-43
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -620,8 +620,9 @@ ERROR(expected_type_function_result,PointsToFirstBadToken,
620620
"expected type for function result", ())
621621
ERROR(generic_non_function,PointsToFirstBadToken,
622622
"only syntactic function types can be generic", ())
623-
ERROR(rethrowing_function_type,PointsToFirstBadToken,
624-
"only function declarations may be marked 'rethrows'", ())
623+
ERROR(rethrowing_function_type,none,
624+
"only function declarations may be marked 'rethrows'; "
625+
"did you mean 'throws'?", ())
625626
ERROR(throws_in_wrong_position,none,
626627
"'throws' may only occur before '->'", ())
627628
ERROR(rethrows_in_wrong_position,none,

lib/Parse/ParseExpr.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2222,7 +2222,8 @@ parseClosureSignatureIfPresent(SmallVectorImpl<CaptureListEntry> &captureList,
22222222
throwsLoc = consumeToken();
22232223
} else if (Tok.is(tok::kw_rethrows)) {
22242224
throwsLoc = consumeToken();
2225-
diagnose(throwsLoc, diag::rethrowing_function_type);
2225+
diagnose(throwsLoc, diag::rethrowing_function_type)
2226+
.fixItReplace(throwsLoc, "throws");
22262227
}
22272228

22282229
// Parse the optional explicit return type.

lib/Parse/ParseType.cpp

Lines changed: 21 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ ParserResult<TypeRepr> Parser::parseSILBoxType(GenericParamList *generics,
254254
///
255255
/// type-function:
256256
/// type-composition '->' type
257+
/// type-composition 'throws' '->' type
257258
///
258259
ParserResult<TypeRepr> Parser::parseType(Diag<> MessageID,
259260
bool HandleCodeCompletion,
@@ -284,62 +285,45 @@ ParserResult<TypeRepr> Parser::parseType(Diag<> MessageID,
284285
parseTypeSimpleOrComposition(MessageID, HandleCodeCompletion);
285286
if (ty.hasCodeCompletion())
286287
return makeParserCodeCompletionResult<TypeRepr>();
287-
288288
if (ty.isNull())
289289
return nullptr;
290+
auto tyR = ty.get();
290291

291-
// Parse a throws specifier. 'throw' is probably a typo for 'throws',
292-
// but in local contexts we could just be at the end of a statement,
293-
// so we need to check for the arrow.
294-
ParserPosition beforeThrowsPos;
292+
// Parse a throws specifier.
293+
// Don't consume 'throws', if the next token is not '->', so we can emit a
294+
// more useful diagnostic when parsing a function decl.
295295
SourceLoc throwsLoc;
296-
bool rethrows = false;
297-
if (Tok.isAny(tok::kw_throws, tok::kw_rethrows) ||
298-
(Tok.is(tok::kw_throw) && peekToken().is(tok::arrow))) {
299-
if (Tok.is(tok::kw_throw)) {
300-
diagnose(Tok.getLoc(), diag::throw_in_function_type)
296+
if (Tok.isAny(tok::kw_throws, tok::kw_rethrows, tok::kw_throw) &&
297+
peekToken().is(tok::arrow)) {
298+
if (Tok.isNot(tok::kw_throws)) {
299+
// 'rethrows' is only allowed on function declarations for now.
300+
// 'throw' is probably a typo for 'throws'.
301+
Diag<> DiagID = Tok.is(tok::kw_rethrows) ?
302+
diag::rethrowing_function_type : diag::throw_in_function_type;
303+
diagnose(Tok.getLoc(), DiagID)
301304
.fixItReplace(Tok.getLoc(), "throws");
302305
}
303-
304-
beforeThrowsPos = getParserPosition();
305-
rethrows = Tok.is(tok::kw_rethrows);
306306
throwsLoc = consumeToken();
307307
}
308308

309-
// Handle type-function if we have an arrow.
310-
SourceLoc arrowLoc;
311-
if (consumeIf(tok::arrow, arrowLoc)) {
309+
if (Tok.is(tok::arrow)) {
310+
// Handle type-function if we have an arrow.
311+
SourceLoc arrowLoc = consumeToken();
312312
ParserResult<TypeRepr> SecondHalf =
313313
parseType(diag::expected_type_function_result);
314314
if (SecondHalf.hasCodeCompletion())
315315
return makeParserCodeCompletionResult<TypeRepr>();
316316
if (SecondHalf.isNull())
317317
return nullptr;
318-
if (rethrows) {
319-
// 'rethrows' is only allowed on function declarations for now.
320-
diagnose(throwsLoc, diag::rethrowing_function_type);
321-
}
322-
auto fnTy = new (Context) FunctionTypeRepr(generics, ty.get(),
323-
throwsLoc,
324-
arrowLoc,
325-
SecondHalf.get());
326-
return makeParserResult(applyAttributeToType(fnTy, inoutLoc, attrs));
327-
} else if (throwsLoc.isValid()) {
328-
// Don't consume 'throws', so we can emit a more useful diagnostic when
329-
// parsing a function decl.
330-
restoreParserPosition(beforeThrowsPos);
331-
}
332-
333-
// Only function types may be generic.
334-
if (generics) {
318+
tyR = new (Context) FunctionTypeRepr(generics, tyR, throwsLoc, arrowLoc,
319+
SecondHalf.get());
320+
} else if (generics) {
321+
// Only function types may be generic.
335322
auto brackets = generics->getSourceRange();
336323
diagnose(brackets.Start, diag::generic_non_function);
337324
}
338325

339-
if (ty.isNonNull() && !ty.hasCodeCompletion()) {
340-
ty = makeParserResult(applyAttributeToType(ty.get(), inoutLoc, attrs));
341-
}
342-
return ty;
326+
return makeParserResult(applyAttributeToType(tyR, inoutLoc, attrs));
343327
}
344328

345329
ParserResult<TypeRepr> Parser::parseTypeForInheritance(

test/Parse/errors.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@ func postRethrows2(_ f: () throws -> Int) -> rethrows Int { // expected-error{{'
122122
return try f()
123123
}
124124

125+
func incompleteThrowType() {
126+
// FIXME: Bad recovery for incomplete function type.
127+
let _: () throws
128+
// expected-error @-1 {{consecutive statements on a line must be separated by ';'}}
129+
// expected-error @-2 {{expected expression}}
130+
}
131+
125132
// rdar://21328447
126133
func fixitThrow0() throw {} // expected-error{{expected throwing specifier; did you mean 'throws'?}} {{20-25=throws}}
127134
func fixitThrow1() throw -> Int {} // expected-error{{expected throwing specifier; did you mean 'throws'?}} {{20-25=throws}}

test/decl/func/rethrows.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
/** Basics *******************************************************************/
44

55
// Function types can't be rethrows right now.
6-
let r1 = {() rethrows -> Int in 0} // expected-error {{only function declarations may be marked 'rethrows'}}
7-
let r2 : () rethrows -> Int = { 0 } // expected-error {{only function declarations may be marked 'rethrows'}}
8-
let r3 : Optional<() rethrows -> ()> = nil // expected-error {{only function declarations may be marked 'rethrows'}}
6+
let r1 = {() rethrows -> Int in 0} // expected-error {{only function declarations may be marked 'rethrows'; did you mean 'throws'?}} {{14-22=throws}}
7+
let r2 : () rethrows -> Int = { 0 } // expected-error {{only function declarations may be marked 'rethrows'; did you mean 'throws'?}} {{13-21=throws}}
8+
let r3 : Optional<() rethrows -> ()> = nil // expected-error {{only function declarations may be marked 'rethrows'; did you mean 'throws'?}} {{22-30=throws}}
99

1010
func f1(_ f: () throws -> ()) rethrows { try f() }
1111
func f2(_ f: () -> ()) rethrows { f() } // expected-error {{'rethrows' function must take a throwing function argument}}

0 commit comments

Comments
 (0)