Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-10520] Compiler incorrectly emits warning when comparing Any and nil #52920

Open
swift-ci opened this issue Apr 19, 2019 · 7 comments
Open
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself

Comments

@swift-ci
Copy link
Collaborator

Previous ID SR-10520
Radar None
Original Reporter schifferer (JIRA User)
Type Bug

Attachment: Download

Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug
Assignee None
Priority Medium

md5: 6bfef07935369a66fd7b3bc5395c61e9

Issue Description:

The type of a Mirror's Child value is Any, which is non-optional. However, when iterating over the children to process each value, some values are nil.

In the attached screenshot, note that the compiler warns that the if-condition will always return false; also note that the debugger has stepped into the if's code block, meaning that the condition was true, because the non-optional value was actually nil.

Since this Stack Overflow answer sufficiently explains why Any can contain a nil value, then the compiler should be aware of this and not emit a warning.

If the build settings were set such that all warnings were promoted to errors (which is a standard practice for some developers for release builds), this particular issue would result in a failed build, even though the code is correct.

@belkadan
Copy link
Contributor

Hm. Any can contain a nil value, but this isn't supposed to be a valid way to check for that, and I'm surprised it's working. @slavapestov, @jckarter?

@jckarter
Copy link
Member

This is behaving correctly, alas. `Any` is a subtype of `Any?`. This ends up invoking the `T? == _NilLiteral` overload, by wrapping the Any in an Any?, and the warning is there to tell you that this is probably not what you want.

@belkadan
Copy link
Contributor

That's what I thought at first, but then it would return false, and the originator says that it steps into the body after all.

@jckarter
Copy link
Member

Maybe the debug info is inaccurate (or we already fixed this)? I just tried a small repro, and it skips over the `if` body as I'd expect:

let x: Int? = nil
let y: Any = x

if y == nil {
  print("test")
}

@swift-ci
Copy link
Collaborator Author

Comment by Paul Schifferer (JIRA)

I'm using Swift 4.2.

If this is fixed in Swift 5, and a value of type Any can still contain nil, then how does one check for that?

@jckarter
Copy link
Member

Do you know for sure that it's executing the body, and the debugger isn't incorrectly placing the breakpoint? I'd want to verify that we don't still have a debugger bug here.

As for checking whether an `Any` contains a `nil`, what are you trying to do with the information? You can do this unfortunately rather circuitous thing to hack around the compiler trying to optimize away the Any-to-Any? check:

func isNilAny(_ value: Any) -> Bool {
  // We need this to hide the `as? Any?` cast from getting short-circuited by the type checker
  func cast<U>(_ value: Any, to: U.Type) -> U? {
    return value as? U
  }

  if let optionalValue = cast(value, to: Any?.self), // if the Any contains an Optional...
     optionalValue == nil { // ...and that optional is nil...
    return true
  }
  return false
}

It might be more constructive to ask the `Any` whether it's one of the types you're expecting it to be, or whether it conforms to a known protocol, rather than try to ask whether it's any kind of Optional at all, though.

@swift-ci
Copy link
Collaborator Author

Comment by Paul Schifferer (JIRA)

I know that I stepped into the if-body once with the debugger, as illustrated in the attached screenshot. (In the course of collecting some information to respond to your other question, I have discovered some issues with my code.) But to summarize, the code in question is attempting to populate a CKRecord by using a Mirror on an arbitrary value object (the class uses a generic for that object's type), and iterating over the Mirror's children.

The function provided in the previous comment addresses my issue, but it still feels like there should be a better way to check for nil on an Any type, since that's a valid value.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself
Projects
None yet
Development

No branches or pull requests

3 participants