mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
We were trying to get fancy rewriting cases where multiple 'if let' clauses were used to unwrap a double optional, but in testing that turned out to be too unreliable. Now we simply detect any 'try?' expressions whose behavior will change, and add an explicit 'as OldType' to the expression, in order to preserve the original behavior.
112 lines
3.1 KiB
Plaintext
112 lines
3.1 KiB
Plaintext
// RUN: %empty-directory(%t)
|
|
// RUN: %target-swift-frontend -c -swift-version 4 -primary-file %s -emit-migrated-file-path %t/optional_try_migration.result.swift
|
|
// RUN: diff -u %S/optional_try_migration.swift.expected %t/optional_try_migration.result.swift
|
|
|
|
func fetchOptInt() throws -> Int? {
|
|
return 3
|
|
}
|
|
|
|
func fetchInt() throws -> Int {
|
|
return 3
|
|
}
|
|
|
|
func fetchAny() throws -> Any {
|
|
return 3
|
|
}
|
|
|
|
func testOnlyMigrateChangedBehavior() {
|
|
// No migration needed
|
|
let _ = try? fetchInt()
|
|
|
|
// Migration needed
|
|
let _ = ((try? fetchOptInt()) as Int??)
|
|
}
|
|
|
|
func testExplicitCasts() {
|
|
|
|
// No migration needed, because there's an explicit cast on the try already
|
|
let _ = (try? fetchOptInt()) as? Int
|
|
|
|
// Migration needed; the 'as? Int' is part of the sub-expression
|
|
let _ = ((try? fetchAny() as? Int) as Int??)
|
|
|
|
// No migration needed; the subexpression is non-optional so behavior has not changed
|
|
let _ = (try? fetchAny()) as? Int
|
|
|
|
// No migration needed, because there's an explicit cast on the try already
|
|
let _ = (try? fetchOptInt()) as! Int // expected-warning {{forced cast from 'Int??' to 'Int' only unwraps optionals; did you mean to use '!!'?}}
|
|
|
|
// No migration needed; the subexpression is non-optional
|
|
let _ = try? fetchAny() as! Int
|
|
|
|
// No migration needed; the subexpression is non-optional so behavior has not changed
|
|
let _ = (try? fetchAny()) as! Int
|
|
|
|
// Migration needed; the explicit cast is not directly on the try?
|
|
let _ = String(describing: ((try? fetchOptInt()) as Int??)) as Any
|
|
|
|
// No migration needed, because the try's subexpression is non-optional
|
|
let _ = String(describing: try? fetchInt()) as Any
|
|
|
|
}
|
|
|
|
func testOptionalChaining() {
|
|
struct Thing {
|
|
func fetchInt() throws -> Int { return 3 }
|
|
func fetchOptInt() throws -> Int { return 3 }
|
|
}
|
|
|
|
let thing = Thing()
|
|
let optThing: Thing? = Thing()
|
|
|
|
// Migration needed
|
|
let _ = ((try? optThing?.fetchInt()) as Int??)
|
|
|
|
// Migration needed
|
|
let _ = ((try? optThing?.fetchOptInt()) as Int??)
|
|
|
|
// No migration needed
|
|
let _ = try? optThing!.fetchOptInt()
|
|
|
|
// No migration needed, because of the explicit cast
|
|
let _ = (try? optThing?.fetchOptInt()) as? Int
|
|
|
|
// Migration needed
|
|
let _ = try? thing.fetchInt()
|
|
|
|
// Migration needed
|
|
let _ = try? thing.fetchOptInt()
|
|
|
|
// No migration needed, because of the explicit cast
|
|
let _ = (try? thing.fetchOptInt()) as! Int // expected-warning {{forced cast from 'Int?' to 'Int' only unwraps optionals; did you mean to use '!'?}}
|
|
}
|
|
|
|
|
|
func testIfLet() {
|
|
|
|
// Migration needed
|
|
if let optionalX = ((try? fetchOptInt()) as Int??),
|
|
let x = optionalX
|
|
{
|
|
print(x)
|
|
}
|
|
|
|
// Don't change 'try?'s that haven't changed behavior
|
|
if let x = try? fetchInt(),
|
|
let y = try? fetchInt() {
|
|
print(x, y)
|
|
}
|
|
}
|
|
|
|
|
|
func testCaseMatching() {
|
|
// Migration needed
|
|
if case let x?? = ((try? fetchOptInt()) as Int??) {
|
|
print(x)
|
|
}
|
|
|
|
// No migration needed
|
|
if case let x? = try? fetchInt() {
|
|
print(x)
|
|
}
|
|
} |