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-12390] Cannot use shorthand key path syntax on PartialKeyPath argument #54827

Closed
Azoy opened this issue Mar 21, 2020 · 4 comments
Closed
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself

Comments

@Azoy
Copy link
Member

Azoy commented Mar 21, 2020

Previous ID SR-12390
Radar rdar://problem/60832858
Original Reporter @Azoy
Type Bug
Status Resolved
Resolution Duplicate
Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug
Assignee None
Priority Medium

md5: ea2f3bb94d68bde84dac2d5e59ff60cd

duplicates:

  • SR-5667 Type inference for Swift 4 KeyPaths fails within collections

is duplicated by:

  • SR-8335 Cannot type check MemoryLayout.offset(of:) without specifying base type in keypath

Issue Description:

I'm trying to use PartialKeyPath as a dictionary key for one of my function arguments, but was surprised to find that the compiler said it was an ambiguous expression when I went to use the shorthand syntax. I tried to isolate it by simply using the key path as the argument and it still didn't work.

Simplified example:

struct Person {
  let name: String
  let age: Int
}

func doFancyThing(with keyPath: PartialKeyPath<Person>) {}

// type of expression is ambiguous
doFancyThing(with: \.age)

// but the following works fine
let age: PartialKeyPath<Person> = \.age

My use case:

func doFancyThing<T>(
  with type: T.Type,
  using keyPaths: [PartialKeyPath<T>: Any]
) {}

// type of expression is ambiguous
doFancyThing(with: Person.self, using: [\.age: 19])

The shorthand syntax works when defining variables, so I assume this is just a bug?

@LucianoPAlmeida
Copy link
Collaborator

Seems like the problem is the solver can't infer the keyPath type by context form the arg conv constraint where

  (tuple_expr type='(with: $T4)' location=... range=... names=with
    (keypath_expr type='$T4' 

and

Resolved overloads:
  selected overload set choice doFancyThing: $T0 == (PartialKeyPath<Person>) -> ()

  ($T4 bindings={(subtypes of) PartialKeyPath<Person>})
  Initial bindings: $T4 := PartialKeyPath<Person>
  (attempting type variable $T4 := PartialKeyPath<Person>
    (failed constraint $T4 key path from $T1 -> $T3 [[locator@0x11d0b2a70 [KeyPath ...]]];)
  )

So, it seems like it is actually failing to find the type KeyPath<Person, Int> for .age because it is failing to find binding of $T1:=Person and $T3 := Int from the context of arg conv.

The exact point where it is failing is here

Can't figure out a solution for this yet, but just sharing some findings here that maybe can be helpful when someone else wants to take a look 🙂

cc @xedin

@beccadax
Copy link
Contributor

@swift-ci create

@LucianoPAlmeida
Copy link
Collaborator

For future reference as @xedin described here
A way to fix this is to use an approach similar to the way closures are type-checked in resolveClosure.
The approach will be to delay the constraint generation(now done in CSGen on visitiKeyPathExpr) until the key path type variable has a contextual type available attempting the binding.
A resolveKeyPath method would perform constraint generation and resolve the key path type together with all key path components as well as resolving the capability of the key path type (read-only, writable ... ). This makes the key path constraint not need anymore, as Pavel mentioned "The reason why key path constraint exists is related to the fact that we need to wait until all of the components are resolved to figure out a capability of the key path (read-only, writable, reference writable)" and now since resolveKeyPath will have context information we would know the capability expected, this only will need to validate that resolved vs expected at this point.
In the end, the resolveKeyPath will perform constraint generation and then resolve the keypath type in a similar way it is being done in ConstraintSystem::simplifyKeyPathConstraint.

This is just a short gist, that could be useful in the future 🙂

@xedin
Copy link
Member

xedin commented Apr 17, 2020

Looks like this is a duplicate of previously reported SR-5667.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
This issue was closed.
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

4 participants