Skip to content

Commit 813a721

Browse files
authored
Merge pull request swiftlang#38674 from hamishknight/following-the-trail
2 parents ebdae7c + 06908ad commit 813a721

File tree

2 files changed

+43
-14
lines changed

2 files changed

+43
-14
lines changed

lib/IDE/Refactoring.cpp

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6901,20 +6901,26 @@ class AsyncConverter : private SourceEntityWalker {
69016901
Scopes.back().Names.insert(ArgName);
69026902
OS << tok::kw_guard << ' ' << tok::kw_let << ' ' << ArgName << ' '
69036903
<< tok::equal << ' ';
6904+
6905+
// If the argument is a call with a trailing closure, the generated
6906+
// guard statement will not compile.
6907+
// e.g. 'guard let result1 = value.map { $0 + 1 } else { ... }'
6908+
// doesn't compile. Adding parentheses makes the code compile.
6909+
auto HasTrailingClosure = false;
6910+
if (auto *CE = dyn_cast<CallExpr>(Arg)) {
6911+
if (CE->getUnlabeledTrailingClosureIndex().hasValue())
6912+
HasTrailingClosure = true;
6913+
}
6914+
6915+
if (HasTrailingClosure)
6916+
OS << tok::l_paren;
6917+
69046918
convertNode(Arg, /*StartOverride=*/CE->getArgumentLabelLoc(ArgIndex),
69056919
/*ConvertCalls=*/false);
6906-
if (auto CE = dyn_cast<CallExpr>(Arg)) {
6907-
if (CE->hasTrailingClosure()) {
6908-
// If the argument is a call with trailing closure, the generated
6909-
// guard statement does not compile.
6910-
// e.g. 'guard let result1 = value.map { $0 + 1 } else { ... }'
6911-
// doesn't compile.
6912-
// Adding a '.self' at the end makes the code compile (although it
6913-
// will still issue a warning about a trailing closure use inside a
6914-
// guard condition).
6915-
OS << tok::period << tok::kw_self;
6916-
}
6917-
}
6920+
6921+
if (HasTrailingClosure)
6922+
OS << tok::r_paren;
6923+
69186924
OS << ' ' << tok::kw_else << ' ' << tok::l_brace << '\n';
69196925
OS << "fatalError" << tok::l_paren;
69206926
OS << "\"Expected non-nil result ";

test/refactoring/ConvertAsync/convert_to_continuation.swift

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ func withoutAsyncAlternativeThrowingWithMultipleResults(closure: @escaping (Int?
1212
func asyncVoidWithoutAlternative(completionHandler2: @escaping () -> Void) {}
1313
func resultWithoutAlternative(completionHandler2: @escaping (Result<Int, Error>) -> Void) {}
1414

15+
func lottaClosures(x: () -> Void, y: () -> Void) -> Int? { nil }
16+
1517
struct MyError: Error {}
1618

1719
// RUN: %refactor-check-compiles -convert-to-async -dump-text -source-filename %s -pos=%(line+1):1 | %FileCheck -check-prefix=CREATE-CONTINUATION %s
@@ -173,7 +175,7 @@ func testThrowingContinuationRelayingErrorAndTwoComplexResults(completionHandler
173175
// THROWING-CONTINUATION-RELAYING-ERROR-AND-TWO-COMPLEX-RESULTS-NEXT: }
174176
// THROWING-CONTINUATION-RELAYING-ERROR-AND-TWO-COMPLEX-RESULTS-NEXT: }
175177

176-
// RUN: %refactor -convert-to-async -dump-text -source-filename %s -pos=%(line+1):1 | %FileCheck -check-prefix=THROWING-CONTINUATION-RELAYING-ERROR-AND-COMPLEX-RESULT-WITH-TRAILING-CLOSURE %s
178+
// RUN: %refactor-check-compiles -convert-to-async -dump-text -source-filename %s -pos=%(line+1):1 | %FileCheck -check-prefix=THROWING-CONTINUATION-RELAYING-ERROR-AND-COMPLEX-RESULT-WITH-TRAILING-CLOSURE %s
177179
func testThrowingContinuationRelayingErrorAndComplexResultWithTrailingClosure(completionHandler: @escaping (Int?, Error?) -> Void) {
178180
withoutAsyncAlternativeThrowing { (theValue, theError) in
179181
completionHandler(theValue.map { $0 + 1 }, theError)
@@ -185,7 +187,7 @@ func testThrowingContinuationRelayingErrorAndComplexResultWithTrailingClosure(co
185187
// THROWING-CONTINUATION-RELAYING-ERROR-AND-COMPLEX-RESULT-WITH-TRAILING-CLOSURE-NEXT: if let error = theError {
186188
// THROWING-CONTINUATION-RELAYING-ERROR-AND-COMPLEX-RESULT-WITH-TRAILING-CLOSURE-NEXT: continuation.resume(throwing: error)
187189
// THROWING-CONTINUATION-RELAYING-ERROR-AND-COMPLEX-RESULT-WITH-TRAILING-CLOSURE-NEXT: } else {
188-
// THROWING-CONTINUATION-RELAYING-ERROR-AND-COMPLEX-RESULT-WITH-TRAILING-CLOSURE-NEXT: guard let result = theValue.map { $0 + 1 }.self else {
190+
// THROWING-CONTINUATION-RELAYING-ERROR-AND-COMPLEX-RESULT-WITH-TRAILING-CLOSURE-NEXT: guard let result = (theValue.map { $0 + 1 }) else {
189191
// THROWING-CONTINUATION-RELAYING-ERROR-AND-COMPLEX-RESULT-WITH-TRAILING-CLOSURE-NEXT: fatalError("Expected non-nil result in the non-error case")
190192
// THROWING-CONTINUATION-RELAYING-ERROR-AND-COMPLEX-RESULT-WITH-TRAILING-CLOSURE-NEXT: }
191193
// THROWING-CONTINUATION-RELAYING-ERROR-AND-COMPLEX-RESULT-WITH-TRAILING-CLOSURE-NEXT: continuation.resume(returning: result)
@@ -194,6 +196,27 @@ func testThrowingContinuationRelayingErrorAndComplexResultWithTrailingClosure(co
194196
// THROWING-CONTINUATION-RELAYING-ERROR-AND-COMPLEX-RESULT-WITH-TRAILING-CLOSURE-NEXT: }
195197
// THROWING-CONTINUATION-RELAYING-ERROR-AND-COMPLEX-RESULT-WITH-TRAILING-CLOSURE-NEXT: }
196198

199+
// RUN: %refactor-check-compiles -convert-to-async -dump-text -source-filename %s -pos=%(line+1):1 | %FileCheck -check-prefix=MULTIPLE-TRAILING-CLOSURES %s
200+
func testThrowingContinuationRelayingErrorAndComplexResultWithMultipleTrailingClosures(completionHandler: @escaping (Int?, Error?) -> Void) {
201+
withoutAsyncAlternativeThrowing { theValue, theError in
202+
completionHandler(lottaClosures {} y: {}, theError)
203+
}
204+
}
205+
// MULTIPLE-TRAILING-CLOSURES: func testThrowingContinuationRelayingErrorAndComplexResultWithMultipleTrailingClosures() async throws -> Int {
206+
// MULTIPLE-TRAILING-CLOSURES-NEXT: return try await withCheckedThrowingContinuation { continuation in
207+
// MULTIPLE-TRAILING-CLOSURES-NEXT: withoutAsyncAlternativeThrowing { theValue, theError in
208+
// MULTIPLE-TRAILING-CLOSURES-NEXT: if let error = theError {
209+
// MULTIPLE-TRAILING-CLOSURES-NEXT: continuation.resume(throwing: error)
210+
// MULTIPLE-TRAILING-CLOSURES-NEXT: } else {
211+
// MULTIPLE-TRAILING-CLOSURES-NEXT: guard let result = (lottaClosures {} y: {}) else {
212+
// MULTIPLE-TRAILING-CLOSURES-NEXT: fatalError("Expected non-nil result in the non-error case")
213+
// MULTIPLE-TRAILING-CLOSURES-NEXT: }
214+
// MULTIPLE-TRAILING-CLOSURES-NEXT: continuation.resume(returning: result)
215+
// MULTIPLE-TRAILING-CLOSURES-NEXT: }
216+
// MULTIPLE-TRAILING-CLOSURES-NEXT: }
217+
// MULTIPLE-TRAILING-CLOSURES-NEXT: }
218+
// MULTIPLE-TRAILING-CLOSURES-NEXT: }
219+
197220
// RUN: %refactor-check-compiles -convert-to-async -dump-text -source-filename %s -pos=%(line+1):1 | %FileCheck -check-prefix=THROWING-CONTINUATION-ALWAYS-RETURNING-ERROR-AND-RESULT %s
198221
func testAlwaysReturnBothResultAndCompletionHandler(completionHandler: @escaping (Int?, Error?) -> Void) {
199222
withoutAsyncAlternativeBecauseOfMismatchedCompletionHandlerName { theValue in

0 commit comments

Comments
 (0)