Swift won't compile dictionary with ReferenceWritableKeyPath unless its a class property

This code compiles just fine:

@objcMembers final class DriversLicense1: NSObject {
    private let map: [String: ReferenceWritableKeyPath<DriversLicense1, String>] = [
        "DAA": \DriversLicense1.nameFull,
    ]
    private(set) var nameFull: String = ""

    override init() {
        super.init()

        for (key, keyPath) in map {
            self[keyPath: keyPath] = key
        }
    }
}

However, this code will not - the error is:

cannot convert value of type 'KeyPath<DriversLicense2, String>' to expected dictionary value type 'ReferenceWritableKeyPath<DriversLicense2, String>'

fileprivate let map: [String: ReferenceWritableKeyPath<DriversLicense2, String>] = [
    "DAA": \DriversLicense2.nameFull,
]
@objcMembers final class DriversLicense2: NSObject {
    private(set) var nameFull: String = ""

    override init() {
        super.init()

        for (key, keyPath) in map {
            self[keyPath: keyPath] = key
        }
    }
}

Why is this?

In the second case, the usage of the key path can’t see the setter. Make the property fileprivate(set) instead and it should work.

1 Like

Stupid noobie mistake by a non-noobie :-( - I just got thrown off by the error message.

Thanks!!!

1 Like

This definitely feels like a place where the diagnostic could be much more helpful—if you try to use the setter directly in the same position you get a better message:

Cannot assign to property: 'nameFull' setter is inaccessible

Seems like we could look at cases where we're attempting a KeyPath -> (Reference)WritableKeyPath conversion and offer a special diagnostic if we could have formed an appropriately writable key path if a setter had been visible in the current scope.

3 Likes