Files
swift-mirror/test/refactoring/ConvertAsync/convert_pattern.swift

568 lines
20 KiB
Swift

// REQUIRES: concurrency
// RUN: %empty-directory(%t)
enum E : Error { case e }
func anyCompletion(_ completion: @escaping (Any?, Error?) -> Void) {}
func anyResultCompletion(_ completion: @escaping (Result<Any?, Error>) -> Void) {}
func stringTupleParam(_ completion: @escaping ((String, String)?, Error?) -> Void) {}
func stringTupleParam() async throws -> (String, String) {}
func stringTupleResult(_ completion: @escaping (Result<(String, String), Error>) -> Void) {}
func stringTupleResult() async throws -> (String, String) {}
func mixedTupleResult(_ completion: @escaping (Result<((Int, Float), String), Error>) -> Void) {}
func mixedTupleResult() async throws -> ((Int, Float), String) {}
func multipleTupleParam(_ completion: @escaping ((String, String)?, (Int, Int)?, Error?) -> Void) {}
func multipleTupleParam() async throws -> ((String, String), (Int, Int)) {}
func testPatterns() async throws {
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=INLINE %s
stringTupleParam { strs, err in
guard let (str1, str2) = strs else { return }
print(str1, str2)
}
// INLINE: let (str1, str2) = try await stringTupleParam()
// INLINE-NEXT: print(str1, str2)
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=INLINE-VAR %s
stringTupleParam { strs, err in
guard var (str1, str2) = strs else { return }
print(str1, str2)
}
// INLINE-VAR: var (str1, str2) = try await stringTupleParam()
// INLINE-VAR-NEXT: print(str1, str2)
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=INLINE-BLANK %s
stringTupleParam { strs, err in
guard var (_, str2) = strs else { return }
print(str2)
}
// INLINE-BLANK: var (_, str2) = try await stringTupleParam()
// INLINE-BLANK-NEXT: print(str2)
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=INLINE-TYPED %s
stringTupleParam { strs, err in
guard let (str1, str2): (String, String) = strs else { return }
print(str1, str2)
}
// INLINE-TYPED: let (str1, str2) = try await stringTupleParam()
// INLINE-TYPED-NEXT: print(str1, str2)
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=INLINE-CASE %s
stringTupleParam { strs, err in
guard case (let str1, var str2)? = strs else { return }
print(str1, str2)
}
// INLINE-CASE: var (str1, str2) = try await stringTupleParam()
// INLINE-CASE-NEXT: print(str1, str2)
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=INLINE-CASE-TYPED %s
stringTupleParam { strs, err in
guard case let (str1, str2)?: (String, String)? = strs else { return }
print(str1, str2)
}
// INLINE-CASE-TYPED: let (str1, str2) = try await stringTupleParam()
// INLINE-CASE-TYPED-NEXT: print(str1, str2)
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=OUT-OF-LINE %s
stringTupleParam { strs, err in
guard let (str1, str2) = strs else { return }
print(str1, str2, strs!)
}
// OUT-OF-LINE: let strs = try await stringTupleParam()
// OUT-OF-LINE-NEXT: let (str1, str2) = strs
// OUT-OF-LINE-NEXT: print(str1, str2, strs)
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=OUT-OF-LINE-VAR %s
stringTupleParam { strs, err in
guard var (str1, _) = strs else { return }
str1 = ""
print(str1, {strs!})
}
// OUT-OF-LINE-VAR: let strs = try await stringTupleParam()
// OUT-OF-LINE-VAR-NEXT: var (str1, _) = strs
// OUT-OF-LINE-VAR-NEXT: str1 = ""
// OUT-OF-LINE-VAR-NEXT: print(str1, {strs})
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=OUT-OF-LINE-CASE %s
stringTupleParam { strs, err in
guard case (let str1, var str2)? = strs else { return }
print(str1, str2, strs!)
}
// OUT-OF-LINE-CASE: let strs = try await stringTupleParam()
// OUT-OF-LINE-CASE-NEXT: var (str1, str2) = strs
// OUT-OF-LINE-CASE-NEXT: print(str1, str2, strs)
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=FALLBACK %s
stringTupleParam { strs, err in
guard let (str1, str2) = strs, str1 == "hi" else { fatalError() }
print(str1, str2, err)
}
// FALLBACK: var strs: (String, String)? = nil
// FALLBACK-NEXT: var err: (any Error)? = nil
// FALLBACK-NEXT: do {
// FALLBACK-NEXT: strs = try await stringTupleParam()
// FALLBACK-NEXT: } catch {
// FALLBACK-NEXT: err = error
// FALLBACK-NEXT: }
// FALLBACK-EMPTY:
// FALLBACK-NEXT: guard let (str1, str2) = strs, str1 == "hi" else { fatalError() }
// FALLBACK-NEXT: print(str1, str2, err)
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=GUARD-AND-UNHANDLED %s
stringTupleParam { strs, err in
guard let (str1, str2) = strs else { fatalError() }
print(str1, str2)
if .random(), err == nil {
print("yay")
} else {
print("nay")
}
}
// GUARD-AND-UNHANDLED: do {
// GUARD-AND-UNHANDLED-NEXT: let (str1, str2) = try await stringTupleParam()
// GUARD-AND-UNHANDLED-NEXT: print(str1, str2)
// GUARD-AND-UNHANDLED-NEXT: if .random(), <#err#> == nil {
// GUARD-AND-UNHANDLED-NEXT: print("yay")
// GUARD-AND-UNHANDLED-NEXT: } else {
// GUARD-AND-UNHANDLED-NEXT: print("nay")
// GUARD-AND-UNHANDLED-NEXT: }
// GUARD-AND-UNHANDLED-NEXT: } catch let err {
// GUARD-AND-UNHANDLED-NEXT: fatalError()
// GUARD-AND-UNHANDLED-NEXT: }
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=MIXED-BINDINGS %s
stringTupleParam { strs, err in
guard let x = strs else { return }
guard var (str1, str2) = strs else { return }
guard var y = strs else { return }
guard let z = strs else { return }
y = ("hello", "there")
print(x, y, z, str1, str2)
}
// Make sure that we
// 1. Coalesce the z binding, as it is a let
// 2. Preserve the y binding, as it is a var
// 3. Print the multi-var binding out of line
//
// MIXED-BINDINGS: let x = try await stringTupleParam()
// MIXED-BINDINGS-NEXT: var (str1, str2) = x
// MIXED-BINDINGS-NEXT: var y = x
// MIXED-BINDINGS-NEXT: y = ("hello", "there")
// MIXED-BINDINGS-NEXT: print(x, y, x, str1, str2)
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=MIXED-BINDINGS2 %s
stringTupleParam { strs, err in
guard var (str1, str2) = strs else { return }
str1 = "hi"
guard var x = strs else { return }
x = ("hello", "there")
print(x, str1, str2)
}
// MIXED-BINDINGS2: var x = try await stringTupleParam()
// MIXED-BINDINGS2-NEXT: var (str1, str2) = x
// MIXED-BINDINGS2-NEXT: str1 = "hi"
// MIXED-BINDINGS2-NEXT: x = ("hello", "there")
// MIXED-BINDINGS2-NEXT: print(x, str1, str2)
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=MIXED-BINDINGS3 %s
stringTupleParam { strs, err in
guard let (str1, str2) = strs else { return }
guard let x = strs else { return }
print(x, str1, str2)
}
// MIXED-BINDINGS3: let x = try await stringTupleParam()
// MIXED-BINDINGS3-NEXT: let (str1, str2) = x
// MIXED-BINDINGS3-NEXT: print(x, str1, str2)
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=ALIAS-BINDINGS %s
stringTupleParam { strs, err in
guard let x = strs else { return }
guard let y = strs else { return }
guard let z = strs else { return }
print(x, y, z)
}
// ALIAS-BINDINGS: let x = try await stringTupleParam()
// ALIAS-BINDINGS-NEXT: print(x, x, x)
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=ALIAS-BINDINGS2 %s
stringTupleParam { strs, err in
guard var x = strs else { return }
guard var y = strs else { return }
guard let z = strs else { return }
print(x, y, z)
}
// ALIAS-BINDINGS2: let z = try await stringTupleParam()
// ALIAS-BINDINGS2-NEXT: var x = z
// ALIAS-BINDINGS2-NEXT: var y = z
// ALIAS-BINDINGS2-NEXT: print(x, y, z)
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=ALIAS-BINDINGS3 %s
stringTupleParam { strs, err in
guard var x = strs else { return }
guard var y = strs else { return }
guard var z = strs else { return }
print(x, y, z)
}
// ALIAS-BINDINGS3: var x = try await stringTupleParam()
// ALIAS-BINDINGS3-NEXT: var y = x
// ALIAS-BINDINGS3-NEXT: var z = x
// ALIAS-BINDINGS3-NEXT: print(x, y, z)
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=ALIAS-BINDINGS4 %s
stringTupleParam { strs, err in
guard var x = strs else { return }
guard let y = strs else { return }
guard let z = strs else { return }
print(x, y, z)
}
// ALIAS-BINDINGS4: let y = try await stringTupleParam()
// ALIAS-BINDINGS4-NEXT: var x = y
// ALIAS-BINDINGS4-NEXT: print(x, y, y)
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=ALIAS-BINDINGS5 %s
stringTupleParam { strs, err in
guard var x = strs else { return }
print(x)
}
// ALIAS-BINDINGS5: var x = try await stringTupleParam()
// ALIAS-BINDINGS5-NEXT: print(x)
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=STRING-TUPLE-RESULT %s
stringTupleResult { res in
switch res {
case .success((let x, let y)):
print(x, y)
case .failure:
print("oh no")
}
}
// STRING-TUPLE-RESULT: do {
// STRING-TUPLE-RESULT-NEXT: let (x, y) = try await stringTupleResult()
// STRING-TUPLE-RESULT-NEXT: print(x, y)
// STRING-TUPLE-RESULT-NEXT: } catch {
// STRING-TUPLE-RESULT-NEXT: print("oh no")
// STRING-TUPLE-RESULT-NEXT: }
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=STRING-TUPLE-RESULT %s
stringTupleResult { res in
switch res {
case let .success((x, y)):
print(x, y)
case .failure:
print("oh no")
}
}
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=MIXED-TUPLE-RESULT %s
mixedTupleResult { res in
if case .failure(let err) = res {
print("oh no")
}
if case .success(((let x, let y), let z)) = res {
print("a", x, y, z)
}
switch res {
case .success(let ((x, _), z)):
print("b", x, z)
case .failure:
print("oh no again")
}
}
// MIXED-TUPLE-RESULT: do {
// MIXED-TUPLE-RESULT-NEXT: let res = try await mixedTupleResult()
// MIXED-TUPLE-RESULT-NEXT: let ((x, y), z) = res
// MIXED-TUPLE-RESULT-NEXT: let ((x1, _), z1) = res
// MIXED-TUPLE-RESULT-NEXT: print("a", x, y, z)
// MIXED-TUPLE-RESULT-NEXT: print("b", x1, z1)
// MIXED-TUPLE-RESULT-NEXT: } catch let err {
// MIXED-TUPLE-RESULT-NEXT: print("oh no")
// MIXED-TUPLE-RESULT-NEXT: print("oh no again")
// MIXED-TUPLE-RESULT-NEXT: }
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=MIXED-TUPLE-RESULT2 %s
mixedTupleResult { res in
switch res {
case .success(((let x, let _), let z)):
print(x, z)
case .failure(let err):
print("oh no \(err)")
}
}
// MIXED-TUPLE-RESULT2: do {
// MIXED-TUPLE-RESULT2-NEXT: let ((x, _), z) = try await mixedTupleResult()
// MIXED-TUPLE-RESULT2-NEXT: print(x, z)
// MIXED-TUPLE-RESULT2-NEXT: } catch let err {
// MIXED-TUPLE-RESULT2-NEXT: print("oh no \(err)")
// MIXED-TUPLE-RESULT2-NEXT: }
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=MIXED-TUPLE-RESULT3 %s
mixedTupleResult { res in
if let ((_, y), z) = try? res.get() {
print(y, z)
} else {
print("boo")
}
}
// MIXED-TUPLE-RESULT3: do {
// MIXED-TUPLE-RESULT3-NEXT: let ((_, y), z) = try await mixedTupleResult()
// MIXED-TUPLE-RESULT3-NEXT: print(y, z)
// MIXED-TUPLE-RESULT3-NEXT: } catch {
// MIXED-TUPLE-RESULT3-NEXT: print("boo")
// MIXED-TUPLE-RESULT3-NEXT: }
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=MULTIPLE-TUPLE-PARAM %s
multipleTupleParam { strs, ints, err in
guard let (str1, str2) = strs, let (int1, int2) = ints else {
print("ohno")
return
}
print(str1, str2, int1, int2)
}
// MULTIPLE-TUPLE-PARAM: do {
// MULTIPLE-TUPLE-PARAM-NEXT: let ((str1, str2), (int1, int2)) = try await multipleTupleParam()
// MULTIPLE-TUPLE-PARAM-NEXT: print(str1, str2, int1, int2)
// MULTIPLE-TUPLE-PARAM-NEXT: } catch let err {
// MULTIPLE-TUPLE-PARAM-NEXT: print("ohno")
// MULTIPLE-TUPLE-PARAM-NEXT: }
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=MULTIPLE-TUPLE-PARAM2 %s
multipleTupleParam { strs, ints, err in
guard let (str1, str2) = strs, var (int1, int2) = ints else {
print("ohno")
return
}
print(str1, str2, int1, int2)
}
// MULTIPLE-TUPLE-PARAM2: do {
// MULTIPLE-TUPLE-PARAM2-NEXT: var ((str1, str2), (int1, int2)) = try await multipleTupleParam()
// MULTIPLE-TUPLE-PARAM2-NEXT: print(str1, str2, int1, int2)
// MULTIPLE-TUPLE-PARAM2-NEXT: } catch let err {
// MULTIPLE-TUPLE-PARAM2-NEXT: print("ohno")
// MULTIPLE-TUPLE-PARAM2-NEXT: }
// RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=MULTIPLE-TUPLE-PARAM3 %s
multipleTupleParam { strs, ints, err in
guard let (str1, str2) = strs, let (int1, int2) = ints else {
print("ohno")
return
}
print(strs!)
print(str1, str2, int1, int2)
}
// MULTIPLE-TUPLE-PARAM3: do {
// MULTIPLE-TUPLE-PARAM3-NEXT: let (strs, (int1, int2)) = try await multipleTupleParam()
// MULTIPLE-TUPLE-PARAM3-NEXT: let (str1, str2) = strs
// MULTIPLE-TUPLE-PARAM3-NEXT: print(strs)
// MULTIPLE-TUPLE-PARAM3-NEXT: print(str1, str2, int1, int2)
// MULTIPLE-TUPLE-PARAM3-NEXT: } catch let err {
// MULTIPLE-TUPLE-PARAM3-NEXT: print("ohno")
// MULTIPLE-TUPLE-PARAM3-NEXT: }
}
// RUN: %refactor -convert-to-async -dump-text -source-filename %s -pos=%(line+1):1 | %FileCheck -check-prefix=NAME-COLLISION %s
func testNameCollision(_ completion: @escaping () -> Void) {
let a = ""
stringTupleParam { strs, err in
guard let (a, b) = strs else { return }
print(a, b)
}
let b = ""
stringTupleParam { strs, err in
guard let (a, b) = strs else { return }
print(a, b, strs!)
}
print(a, b)
completion()
}
// TODO: `throws` isn't added to the function declaration
// NAME-COLLISION: func testNameCollision() async {
// NAME-COLLISION-NEXT: let a = ""
// NAME-COLLISION-NEXT: let (a1, b) = try await stringTupleParam()
// NAME-COLLISION-NEXT: print(a1, b)
// NAME-COLLISION-NEXT: let b1 = ""
// NAME-COLLISION-NEXT: let strs = try await stringTupleParam()
// NAME-COLLISION-NEXT: let (a2, b2) = strs
// NAME-COLLISION-NEXT: print(a2, b2, strs)
// NAME-COLLISION-NEXT: print(a, b1)
// NAME-COLLISION-NEXT: return
// NAME-COLLISION-NEXT: }
// RUN: %refactor -convert-to-async -dump-text -source-filename %s -pos=%(line+1):1 | %FileCheck -check-prefix=NAME-COLLISION2 %s
func testNameCollision2(_ completion: @escaping () -> Void) {
mixedTupleResult { res in
guard case let .success((x, y), z) = res else { return }
stringTupleParam { strs, err in
if let (x, y) = strs {
print("a", x, y)
}
}
print("b", x, y, z)
}
}
// TODO: `throws` isn't added to the function declaration
// NAME-COLLISION2: func testNameCollision2() async {
// NAME-COLLISION2-NEXT: let ((x, y), z) = try await mixedTupleResult()
// NAME-COLLISION2-NEXT: let (x1, y1) = try await stringTupleParam()
// NAME-COLLISION2-NEXT: print("a", x1, y1)
// NAME-COLLISION2-NEXT: print("b", x, y, z)
// NAME-COLLISION2-NEXT: }
// Cannot use refactor-check-compiles, as cannot pattern match with placeholders.
// RUN: %refactor -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):1 | %FileCheck -check-prefix=TEST-UNHANDLED %s
anyCompletion { val, err in
if let x = val {
print("a")
}
if let _ = val {
print("b")
}
if case let x? = val {
print("c")
}
if case let _? = val {
print("d")
}
if case E.e? = val {
print("e")
}
if case (let x as String)? = val {
print("f")
}
if case let "" as String = val {
print("g")
}
}
// TEST-UNHANDLED: let x = try await anyCompletion()
// TEST-UNHANDLED-NEXT: print("a")
// TEST-UNHANDLED-NEXT: print("b")
// TEST-UNHANDLED-NEXT: print("c")
// TEST-UNHANDLED-NEXT: print("d")
// TEST-UNHANDLED-NEXT: if case E.e? = <#x#> {
// TEST-UNHANDLED-NEXT: print("e")
// TEST-UNHANDLED-NEXT: }
// TEST-UNHANDLED-NEXT: if case (let x as String)? = <#x#> {
// TEST-UNHANDLED-NEXT: print("f")
// TEST-UNHANDLED-NEXT: }
// TEST-UNHANDLED-NEXT: if case let "" as String = <#x#> {
// TEST-UNHANDLED-NEXT: print("g")
// TEST-UNHANDLED-NEXT: }
// RUN: not %refactor -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):1
anyResultCompletion { res in
switch res {
case .success(let unwrapped?):
print(unwrapped)
case .success(let x):
print(x)
case .failure:
print("oh no")
}
}
// RUN: not %refactor -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):1
anyResultCompletion { res in
switch res {
case .success(let str as String):
print(str)
case .success(let x):
print(x)
case .failure:
print("oh no")
}
}
// RUN: not %refactor -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):1
anyResultCompletion { res in
switch res {
case .success(E.e?):
print("ee")
case .success(let x):
print(x)
case .failure:
print("oh no")
}
}
// RUN: not %refactor -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):1
anyResultCompletion { res in
switch res {
case .success("" as String):
print("empty string")
case .success(let x):
print(x)
case .failure:
print("oh no")
}
}
// FIXME: This should ideally be turned into a 'catch let e as E'.
// RUN: not %refactor -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):1
anyResultCompletion { res in
switch res {
case .success(let a):
print(a)
case .failure(let e as E):
print("oh no e")
case .failure:
print("oh no")
}
}
// FIXME: This should ideally be turned into a 'catch E.e'.
// RUN: not %refactor -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):1
anyResultCompletion { res in
switch res {
case .success(let a):
print(a)
case .failure(E.e):
print("oh no ee")
case .failure:
print("oh no")
}
}
// Make sure we handle a capture list okay.
class C {
// RUN: %refactor-check-compiles -convert-to-async -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=CAPTURE %s
func foo() {
let _ = { [weak self] in
print(self!)
}
}
}
// CAPTURE: func foo() async {
// CAPTURE-NEXT: let _ = { [weak self] in
// CAPTURE-NEXT: print(self!)
// CAPTURE-NEXT: }
// CAPTURE-NEXT: }