Files
swift-mirror/test/Migrator/optional_try_migration.swift
BJ Homer f166b0da3d Make the try? migration simpler and more reliable.
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.
2018-11-14 01:10:00 -07:00

112 lines
3.0 KiB
Swift

// 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()
}
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
// 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 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()
// Migration needed
let _ = try? optThing?.fetchOptInt()
// 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(),
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() {
print(x)
}
// No migration needed
if case let x? = try? fetchInt() {
print(x)
}
}