mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Adds three refactorings intended to help users migrate their existing code to use the new async language features: 1. Convert call to use async alternative 2. Convert function to async 3. Add async alternative function A function is considered to have an async alternative if it has a void return type and has a void returning closure as its last parameter. A method to explicitly mark functions as having an async alternative may be added to make this more accurate in the future (required for eg. a warning about a call to the non-async version of a function in an async context). (1) converts a call to use the new `await` async language syntax. If the async alternative throws, it will also add `try`. The closure itself is hoisted out of the call, see the comments on `AsyncConversionStringBuilder` for specifics. (2) converts a whole function to `async`, using (1) to convert any calls in the function to their async alternatives. (3) is similar to (2), but instead *adds* a function and replaces calls to its completion/handler/callback closure parameter with `return` or `throws`. Resolves rdar://68254700
137 lines
4.5 KiB
Swift
137 lines
4.5 KiB
Swift
enum CustomError : Error {
|
|
case Bad
|
|
}
|
|
|
|
func simple(_ completion: (String) -> Void) { }
|
|
func simple2(arg: String, _ completion: (String) -> Void) { }
|
|
func simpleErr(arg: String, _ completion: (String?, Error?) -> Void) { }
|
|
func simpleRes(arg: String, _ completion: (Result<String, Error>) -> Void) { }
|
|
func run(block: () -> Bool) -> Bool { return false }
|
|
|
|
// RUN: %refactor -convert-to-async -dump-text -source-filename %s -pos=%(line+1):1 | %FileCheck -check-prefix=NESTED %s
|
|
func nested() {
|
|
simple {
|
|
simple2(arg: $0) { str2 in
|
|
print(str2)
|
|
}
|
|
}
|
|
}
|
|
// NESTED: func nested() async {
|
|
// NESTED-NEXT: let val0 = await simple()
|
|
// NESTED-NEXT: let str2 = await simple2(arg: val0)
|
|
// NESTED-NEXT: print(str2)
|
|
// NESTED-NEXT: }
|
|
|
|
// RUN: %refactor -convert-to-async -dump-text -source-filename %s -pos=%(line+1):1 | %FileCheck -check-prefix=MANY-NESTED %s
|
|
func manyNested() {
|
|
simple { str1 in
|
|
print("simple")
|
|
simple2(arg: str1) { str2 in
|
|
print("simple2")
|
|
simpleErr(arg: str2) { str3, err in
|
|
print("simpleErr")
|
|
guard let str3 = str3, err == nil else {
|
|
return
|
|
}
|
|
simpleRes(arg: str3) { res in
|
|
print("simpleRes")
|
|
if case .success(let str4) = res {
|
|
print("\(str1) \(str2) \(str3) \(str4)")
|
|
print("after")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// MANY-NESTED: func manyNested() async {
|
|
// MANY-NESTED-NEXT: let str1 = await simple()
|
|
// MANY-NESTED-NEXT: print("simple")
|
|
// MANY-NESTED-NEXT: let str2 = await simple2(arg: str1)
|
|
// MANY-NESTED-NEXT: print("simple2")
|
|
// MANY-NESTED-NEXT: let str3 = try await simpleErr(arg: str2)
|
|
// MANY-NESTED-NEXT: print("simpleErr")
|
|
// MANY-NESTED-NEXT: let str4 = try await simpleRes(arg: str3)
|
|
// MANY-NESTED-NEXT: print("simpleRes")
|
|
// MANY-NESTED-NEXT: print("\(str1) \(str2) \(str3) \(str4)")
|
|
// MANY-NESTED-NEXT: print("after")
|
|
// MANY-NESTED-NEXT: }
|
|
|
|
// RUN: %refactor -add-async-alternative -dump-text -source-filename %s -pos=%(line+1):1 | %FileCheck -check-prefix=ASYNC-SIMPLE %s
|
|
func asyncParams(arg: String, _ completion: (String?, Error?) -> Void) {
|
|
simpleErr(arg: arg) { str, err in
|
|
print("simpleErr")
|
|
guard let str = str, err == nil else {
|
|
completion(nil, err!)
|
|
return
|
|
}
|
|
completion(str, nil)
|
|
print("after")
|
|
}
|
|
}
|
|
// ASYNC-SIMPLE: func {{[a-zA-Z_]+}}(arg: String) async throws -> String {
|
|
// ASYNC-SIMPLE-NEXT: let str = try await simpleErr(arg: arg)
|
|
// ASYNC-SIMPLE-NEXT: print("simpleErr")
|
|
// ASYNC-SIMPLE-NEXT: return str
|
|
// ASYNC-SIMPLE-NEXT: print("after")
|
|
// ASYNC-SIMPLE-NEXT: }
|
|
|
|
// RUN: %refactor -add-async-alternative -dump-text -source-filename %s -pos=%(line+1):1 | %FileCheck -check-prefix=ASYNC-SIMPLE %s
|
|
func asyncResErrPassed(arg: String, _ completion: (Result<String, Error>) -> Void) {
|
|
simpleErr(arg: arg) { str, err in
|
|
print("simpleErr")
|
|
guard let str = str, err == nil else {
|
|
completion(.failure(err!))
|
|
return
|
|
}
|
|
completion(.success(str))
|
|
print("after")
|
|
}
|
|
}
|
|
|
|
// RUN: %refactor -add-async-alternative -dump-text -source-filename %s -pos=%(line+1):1 | %FileCheck -check-prefix=ASYNC-ERR %s
|
|
func asyncResNewErr(arg: String, _ completion: (Result<String, Error>) -> Void) {
|
|
simpleErr(arg: arg) { str, err in
|
|
print("simpleErr")
|
|
guard let str = str, err == nil else {
|
|
completion(.failure(CustomError.Bad))
|
|
return
|
|
}
|
|
completion(.success(str))
|
|
print("after")
|
|
}
|
|
}
|
|
// ASYNC-ERR: func asyncResNewErr(arg: String) async throws -> String {
|
|
// ASYNC-ERR-NEXT: do {
|
|
// ASYNC-ERR-NEXT: let str = try await simpleErr(arg: arg)
|
|
// ASYNC-ERR-NEXT: print("simpleErr")
|
|
// ASYNC-ERR-NEXT: return str
|
|
// ASYNC-ERR-NEXT: print("after")
|
|
// ASYNC-ERR-NEXT: } catch let err {
|
|
// ASYNC-ERR-NEXT: throw CustomError.Bad
|
|
// ASYNC-ERR-NEXT: }
|
|
// ASYNC-ERR-NEXT: }
|
|
|
|
// RUN: %refactor -add-async-alternative -dump-text -source-filename %s -pos=%(line+1):1 | %FileCheck -check-prefix=ASYNC-UNHANDLED %s
|
|
func asyncUnhandledCompletion(_ completion: (String) -> Void) {
|
|
simple { str in
|
|
let success = run {
|
|
completion(str)
|
|
return true
|
|
}
|
|
if !success {
|
|
completion("bad")
|
|
}
|
|
}
|
|
}
|
|
// ASYNC-UNHANDLED: func asyncUnhandledCompletion() async -> String {
|
|
// ASYNC-UNHANDLED-NEXT: let str = await simple()
|
|
// ASYNC-UNHANDLED-NEXT: let success = run {
|
|
// ASYNC-UNHANDLED-NEXT: <#completion#>(str)
|
|
// ASYNC-UNHANDLED-NEXT: return true
|
|
// ASYNC-UNHANDLED-NEXT: }
|
|
// ASYNC-UNHANDLED-NEXT: if !success {
|
|
// ASYNC-UNHANDLED-NEXT: return "bad"
|
|
// ASYNC-UNHANDLED-NEXT: }
|
|
// ASYNC-UNHANDLED-NEXT: }
|