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-6655] x == nil works by Optional promotion if x is Any #49204

Open
swift-ci opened this issue Dec 21, 2017 · 11 comments
Open

[SR-6655] x == nil works by Optional promotion if x is Any #49204

swift-ci opened this issue Dec 21, 2017 · 11 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. standard library Area: Standard library umbrella

Comments

@swift-ci
Copy link
Collaborator

Previous ID SR-6655
Radar rdar://problem/36257700
Original Reporter sorenmortensen (JIRA User)
Type Bug
Environment

macOS High Sierra 10.13.1 (17B1003), Xcode 9.2 (9C40b), Swift 4.0.3 (swiftlang-900.0.74.1 clang-900.0.39.2)

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

md5: 120990bfcfaeff313fd7e17d9d956592

Issue Description:

A comparison with nil of the value of an Optional property accessed through a PartialKeyPath doesn't return true if the value is nil. Example:

struct Foo {
    var bar: String?
}

let baz = Foo(bar: nil)
let path: PartialKeyPath<Foo> = \Foo.bar
let isNil = baz[keyPath: path] == nil

print(isNil) // prints "false"
@belkadan
Copy link
Contributor

belkadan commented Jan 2, 2018

I at least get a warning for this:

<stdin>:7:32: warning: comparing non-optional value of type 'Any' to nil always returns false
let isNil = baz[keyPath: path] == nil
            ~~~~~~~~~~~~~~~~~~ ^  ~~~

and I'm not sure quite what we'd want to do about it. @jckarter, @moiseev, any thoughts?

@jckarter
Copy link
Member

jckarter commented Jan 2, 2018

I don't think this is specific to key paths, this is an overload resolution problem because of the weird special-case Optional == _OptionalNilComparisonType hack to make x != nil work even when x isn't Equatable. cc @DougGregor

@jckarter
Copy link
Member

jckarter commented Jan 2, 2018

@swift-ci create

@belkadan
Copy link
Contributor

belkadan commented Jan 2, 2018

That's true, but we could make that work if we wanted to. I'm just not sure whether we want to.

@jckarter
Copy link
Member

jckarter commented Jan 2, 2018

Sorry I wasn't clear. I'm trying to say it does work today, and it apparently also works by accident when `x` isn't statically Optional.

@belkadan
Copy link
Contributor

belkadan commented Jan 2, 2018

It prints false. It could print true by looking inside the Any.

@jckarter
Copy link
Member

jckarter commented Jan 2, 2018

I see what you're saying now. That's not really correct by the current design, though, since the operation is receiving an Any? containing .some(x), and the intended meaning of == nil is really "matches .none".

@belkadan
Copy link
Contributor

belkadan commented Jan 2, 2018

I'd normally agree, but the fact that we bridge nil optionals to NSNull in non-optional contexts is what made me not sure. But I don't feel strongly about it.

@DougGregor
Copy link
Member

Looking inside the Any isn't something we express in the language today. The runtime could do it with some tricks, but it feels like peeking inside the Any for this operation would create more surprises elsewhere, if one expects other parts of the language to look through an Any. We have the warning due to the potential for surprise here. Personally, I don't think we should make any other changes.

@swift-ci
Copy link
Collaborator Author

Comment by Cory Alder (JIRA)

I was attempting to use keyPaths to write a validator, that would take an object and return a list of keypaths that have nil values. But I get this weird behavior:

struct Person {
    let name: String?
    let date: Date?
}

let person = Person(name: "hello", date: nil)
let paths = [\Person.name, \Person.date]

let resolved = paths.map { person[keyPath: $0] }
// resolved is: [Optional("hello"), nil]
let filtered = resolved.filter { $0 == nil }
// filtered is: []

Namely, I would expect `filtered` to contain one nil value, instead of no values. It looks like this is because `person[keyPath: $0]` is returning `Any` instead of `Any?` but disambiguating those does not seem possible?

related: https://bugs.swift.org/browse/SR-5667

@belkadan
Copy link
Contributor

The compiler is just looking at an array containing KeyPath<Person, String?> and KeyPath<Person, Date?> and deciding that the best common type is PartialKeyPath<Person>. Swift doesn't have the notion of covariant generic parameters required for the compiler to even consider using KeyPath<Person, Any?> instead.

@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. standard library Area: Standard library umbrella
Projects
None yet
Development

No branches or pull requests

4 participants