// REQUIRES: concurrency // RUN: %empty-directory(%t) func simpleWithError(completion: @escaping (String?, Error?) -> Void) {} func simpleWithError() async throws -> String {} func testPathClassification() async throws { // Both of these test cases should produce the same refactoring. // RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=ELSE-IF-CLASSIFICATION %s simpleWithError { str, err in if err == nil { print("a") } else if .random() { print("b") } else { print("c") } if err != nil { print("d") } else if .random() { print("e") } else { print("f") } } // RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=ELSE-IF-CLASSIFICATION %s simpleWithError { str, err in if let str = str { print("a") } else if .random() { print("b") } else { print("c") } if str == nil { print("d") } else if .random() { print("e") } else { print("f") } } // ELSE-IF-CLASSIFICATION: do { // ELSE-IF-CLASSIFICATION-NEXT: let str = try await simpleWithError() // ELSE-IF-CLASSIFICATION-NEXT: print("a") // ELSE-IF-CLASSIFICATION-NEXT: if .random() { // ELSE-IF-CLASSIFICATION-NEXT: print("e") // ELSE-IF-CLASSIFICATION-NEXT: } else { // ELSE-IF-CLASSIFICATION-NEXT: print("f") // ELSE-IF-CLASSIFICATION-NEXT: } // ELSE-IF-CLASSIFICATION-NEXT: } catch let err { // ELSE-IF-CLASSIFICATION-NEXT: if .random() { // ELSE-IF-CLASSIFICATION-NEXT: print("b") // ELSE-IF-CLASSIFICATION-NEXT: } else { // ELSE-IF-CLASSIFICATION-NEXT: print("c") // ELSE-IF-CLASSIFICATION-NEXT: } // ELSE-IF-CLASSIFICATION-NEXT: print("d") // ELSE-IF-CLASSIFICATION-NEXT: } // RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=ELSE-IF-CLASSIFICATION2 %s simpleWithError { str, err in if err == nil { print("a") } else if .random() { print("b") } if .random() { print("c") } if err != nil, .random() { print("d") } } // Make sure the classification of 'b' into the error block doesn't affect the // handling of 'c'. // ELSE-IF-CLASSIFICATION2: do { // ELSE-IF-CLASSIFICATION2-NEXT: let str = try await simpleWithError() // ELSE-IF-CLASSIFICATION2-NEXT: print("a") // ELSE-IF-CLASSIFICATION2-NEXT: if .random() { // ELSE-IF-CLASSIFICATION2-NEXT: print("c") // ELSE-IF-CLASSIFICATION2-NEXT: } // ELSE-IF-CLASSIFICATION2-NEXT: } catch let err { // ELSE-IF-CLASSIFICATION2-NEXT: if .random() { // ELSE-IF-CLASSIFICATION2-NEXT: print("b") // ELSE-IF-CLASSIFICATION2-NEXT: } // ELSE-IF-CLASSIFICATION2-NEXT: if <#err#> != nil, .random() { // ELSE-IF-CLASSIFICATION2-NEXT: print("d") // ELSE-IF-CLASSIFICATION2-NEXT: } // ELSE-IF-CLASSIFICATION2-NEXT: } // FIXME: This case is a little tricky: Being in the else block of 'err == nil' // should allow us to place 'if let str = str' in the failure block. However, this // is a success condition, so we still place it in the success block. Really what // we need to do here is check to see if simpleWithError has an existing async // alternative that still returns optional success values, and allow success // classification in that case. Otherwise, we'd probably be better off leaving // the condition unhandled, as it's not clear what the user is doing. // RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=ELSE-IF-CLASSIFICATION3 %s simpleWithError { str, err in if err == nil { print("a") } else if let str = str { print("b") } else { print("c") } } // ELSE-IF-CLASSIFICATION3: do { // ELSE-IF-CLASSIFICATION3-NEXT: let str = try await simpleWithError() // ELSE-IF-CLASSIFICATION3-NEXT: print("a") // ELSE-IF-CLASSIFICATION3-NEXT: print("b") // ELSE-IF-CLASSIFICATION3-NEXT: } catch let err { // ELSE-IF-CLASSIFICATION3-NEXT: print("c") // ELSE-IF-CLASSIFICATION3-NEXT: } // FIXME: Similar to the case above. // RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=ELSE-IF-CLASSIFICATION4 %s simpleWithError { str, err in if err == nil { print("a") } else if let str = str { print("b") } else if .random() { print("c") } else { print("d") } } // ELSE-IF-CLASSIFICATION4: do { // ELSE-IF-CLASSIFICATION4-NEXT: let str = try await simpleWithError() // ELSE-IF-CLASSIFICATION4-NEXT: print("a") // ELSE-IF-CLASSIFICATION4-NEXT: print("b") // ELSE-IF-CLASSIFICATION4-NEXT: } catch let err { // ELSE-IF-CLASSIFICATION4-NEXT: if .random() { // ELSE-IF-CLASSIFICATION4-NEXT: print("c") // ELSE-IF-CLASSIFICATION4-NEXT: } else { // ELSE-IF-CLASSIFICATION4-NEXT: print("d") // ELSE-IF-CLASSIFICATION4-NEXT: } // ELSE-IF-CLASSIFICATION4-NEXT: } // RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=ELSE-IF-CLASSIFICATION5 %s simpleWithError { str, err in if let err = err { print("a") } else if let str = str { print("b") return } else if .random() { print("c") } else { print("d") } } // ELSE-IF-CLASSIFICATION5: do { // ELSE-IF-CLASSIFICATION5-NEXT: let str = try await simpleWithError() // ELSE-IF-CLASSIFICATION5-NEXT: print("b") // ELSE-IF-CLASSIFICATION5-NEXT: } catch let err { // ELSE-IF-CLASSIFICATION5-NEXT: print("a") // ELSE-IF-CLASSIFICATION5-NEXT: if .random() { // ELSE-IF-CLASSIFICATION5-NEXT: print("c") // ELSE-IF-CLASSIFICATION5-NEXT: } else { // ELSE-IF-CLASSIFICATION5-NEXT: print("d") // ELSE-IF-CLASSIFICATION5-NEXT: } // ELSE-IF-CLASSIFICATION5-NEXT: } // Cannot use refactor-check-compiles, as 'err' cannot have its type inferred // from placeholder. // RUN: %refactor -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=IF-LET-RETURN-CLASSIFICATION %s simpleWithError { str, err in if let str = str { print("a") return } if .random(), let err = err { print("b") } else { print("c") } } // IF-LET-RETURN-CLASSIFICATION: do { // IF-LET-RETURN-CLASSIFICATION-NEXT: let str = try await simpleWithError() // IF-LET-RETURN-CLASSIFICATION-NEXT: print("a") // IF-LET-RETURN-CLASSIFICATION-NEXT: } catch let err { // IF-LET-RETURN-CLASSIFICATION-NEXT: if .random(), let err = <#err#> { // IF-LET-RETURN-CLASSIFICATION-NEXT: print("b") // IF-LET-RETURN-CLASSIFICATION-NEXT: } else { // IF-LET-RETURN-CLASSIFICATION-NEXT: print("c") // IF-LET-RETURN-CLASSIFICATION-NEXT: } // IF-LET-RETURN-CLASSIFICATION-NEXT: } // RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=GUARD-CLASSIFICATION %s simpleWithError { str, err in guard let str = str else { print("a") return } guard err == nil, .random() else { print("b") return } print("c") } // GUARD-CLASSIFICATION: do { // GUARD-CLASSIFICATION-NEXT: let str = try await simpleWithError() // GUARD-CLASSIFICATION-NEXT: guard <#err#> == nil, .random() else { // GUARD-CLASSIFICATION-NEXT: print("b") // GUARD-CLASSIFICATION-NEXT: <#return#> // GUARD-CLASSIFICATION-NEXT: } // GUARD-CLASSIFICATION-NEXT: print("c") // GUARD-CLASSIFICATION-NEXT: } catch let err { // GUARD-CLASSIFICATION-NEXT: print("a") // GUARD-CLASSIFICATION-NEXT: } // RUN: %refactor-check-compiles -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=SILLY-CLASSIFICATION %s simpleWithError { str, err in guard let str = str else { return } guard let err = err else { return } print("urr") } // In this case we just take whichever guard is last. // SILLY-CLASSIFICATION: do { // SILLY-CLASSIFICATION-NEXT: let str = try await simpleWithError() // SILLY-CLASSIFICATION-NEXT: } catch let err { // SILLY-CLASSIFICATION-NEXT: print("urr") // SILLY-CLASSIFICATION-NEXT: } }