swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.3k stars 10.34k forks source link

[SR-8731] Distinct results for nullity checking #51240

Open swift-ci opened 6 years ago

swift-ci commented 6 years ago
Previous ID SR-8731
Radar None
Original Reporter luiswdy (JIRA User)
Type Bug

Attachment: Download

Environment iOS 11, Xcode 9.4, Swift 4.1 iOS 12, Xcode 10 beta 6, Swift 4.2
Additional Detail from JIRA | | | |------------------|-----------------| |Votes | 0 | |Component/s | Compiler | |Labels | Bug, 4.2Regression, TypeChecker | |Assignee | None | |Priority | Medium | md5: 426f1ff173e8149553c083039341e8b4

Issue Description:

When running a piece of code in Xcode's playground (please refer the attachment), Xcode 9.4 and Xcode 10 got distinct results

In Xcode 9.4 playground I got false, yet Xcode 10 beta 6 I got true. Perhaps swift compiler changed its way to resolve generics and then led the issue. I haven't reasoned which of results sounds more logical; therefore I am not sure whether this is a bug.

belkadan commented 6 years ago
typealias S = String
typealias T = Any

func pickSomething(_ items: [S]) -> S? {
    return items.first
}

func doSomething<T>() -> T? {
    return pickSomething([]) as? T
}

func doSomething() -> S? {
    return pickSomething([])
}

let result = doSomething() as Any? != nil
print("result: \(result)")

@rudkx, you've been looking at these lately, right?

hamishknight commented 6 years ago

This is similar to https://bugs.swift.org/browse/SR-8725 – and is due to a change where the compiler is now more conservative with unwrapping an optional value that's being cast to a generic placeholder type.

Now, the results you get are consistent with those that you would get in a non-generic context, for example:

typealias S = String

func pickSomething(_ items: [S]) -> S? {
  return items.first
}

func doSomething<T>() -> T? {
  return pickSomething([]) as? T
}

let result1 = doSomething() as Any?
print(result1 as Any) // Optional(nil)

let result2 = pickSomething([]) as? Any?
print(result2 as Any) // Optional(nil)

However this change wasn't properly gated by Swift version – I'm working on restoring the old behaviour under Swift 4 mode (https://github.com/apple/swift/pull/19217).