`\.value.count` vs. `\value.count` KeyPath

What's up with this latter syntax? Did I miss something? Is it a bug or by design?

struct S {
  var value: [Int] = []
  func foo(_: KeyPath<S, Int> = \.value.count) {}
  func bar(_: KeyPath<S, Int> = \value.count) {}
}

This code compiles just fine. It's also interesting because the latter syntax works as a short-hand form for this property wrapper.

@propertyWrapper
struct Derived<Root, Value> {
  var wrappedValue: Value {
    get { fatalError() }
    set { fatalError() }
  }
​
  let keyPath: ReferenceWritableKeyPath<Root, Value>
​
  init(_ keyPath: ReferenceWritableKeyPath<Root, Value>) {
    self.keyPath = keyPath
  }
​
  static subscript(
    _enclosingInstance instance: Root,
    wrapped wrappedKeyPath: ReferenceWritableKeyPath<Root, Value>,
    storage storageKeyPath: ReferenceWritableKeyPath<Root, Self>
  ) -> Value {
    get {
      instance[keyPath: instance[keyPath: storageKeyPath].keyPath]
    }
    set {
      instance[keyPath: instance[keyPath: storageKeyPath].keyPath] = newValue
    }
  }
}
​
​
class Parent: UIView {
  private let label = UILabel()
​
  @Derived(\label.text)
  var text: String?
}
​
let instance = Parent()
instance.text // nil
instance.text = "foo"

cc @Joe_Groff

1 Like

That looks like a bug to me.

3 Likes

Okay, I'll file a bug, it was too good to be true as a short-hand form. :smiley:

https://bugs.swift.org/browse/SR-12290

Hmm, I thought the parser would diagnose the missing period but it doesn't. It just parses the rest of the key path expression without diagnosing.

Another weird issue:
When I change your example of the usage of the Derived wrapper to include the . as such:

@Derived(\.label.text)

I get a compiler error: Type of expression is ambiguous without more context
But without the ., the code compiles just fine without any ambiguities.
Is this perhaps another bug?

I tested on Swift 5.1.3 (Xcode 11.3) and Swift 5.2 beta included in Xcode 11.4.

It seems like the context isn't taken into consideration for type inference. You can just add a type name for now I suppose.

1 Like

I donβ€˜t think thatβ€˜s a bug though. If you completely desugar this property wrapper, there is no context that would provide the Root type. The computed property isnβ€˜t directly connected to the stored property to infer its type from.

1 Like