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

Infer closure type from context #740

Closed
fesor opened this issue May 13, 2018 · 6 comments
Closed

Infer closure type from context #740

fesor opened this issue May 13, 2018 · 6 comments
Labels
enhancement hard problems Problems without an obvious easy solution wontfix

Comments

@fesor
Copy link

fesor commented May 13, 2018

Let's say we have simple function

/**
 * @template T
 * @param T[] $items
 * @param Closure(T): bool
 * @return \Generator<int, T>
 */
function filter(array $items, \Closure $fn) {
  foreach ($items as $item) {
    if ($fn($item)) {
      yield $item;
    }
  }
}

Right now psalm is unable to infer types for closure from this declaration

/** @var Item[] $arr */
$filtered = filter($arr, function ($item) {
    return $item->enabled();
})

Parameter $item has no provided type, could not infer type

example:

https://getpsalm.org/r/1a8f1377b0

@fesor fesor changed the title infer closure arguments from context Infer closure type from context May 13, 2018
@muglug
Copy link
Collaborator

muglug commented May 13, 2018

Psalm can’t currently infer closure types depending on how those closures are used.

Evaluation for function/method calls is:

  1. arguments are evaluated in order
  2. function arguments checked (to test whether params & args match) and templated params are gathered up for the given call
  3. return type is generated for that method call, given the templated parameters

In your example it would possible to figure out the types in step 1, but not if the param order was swapped. In that scenario, there’d have to be another sweep to collect all templated types in args, and solve for x (or T, here)

@fesor
Copy link
Author

fesor commented May 16, 2018

@muglug could you provide example with swapped param order? I don't quite understand.

@muglug
Copy link
Collaborator

muglug commented Sep 25, 2018

Sorry, let this one slip.

$gen = filter($collection, function ($item){
    return $item->check(13);    
});

could work because we'd identify that $collection is of type T[] which means T = Item, then know that the untyped param in function ($item) ... should be of type Item because it matches Closure(T) in the called function.

But reverse the parameters so the closure is the first arg, and Psalm wouldn't know what to do:

$gen = filter(function ($item){
    return $item->check(13);    
}, $collection);

Now $item is a mystery type, and we don't know what happens when we evaluate $item->check(13).

To solve this we'd have to do a second pass to resolve all templated types, and that's not massively ideal.

@muglug muglug added hard problems Problems without an obvious easy solution wontfix labels Jan 6, 2019
@muglug
Copy link
Collaborator

muglug commented Jan 6, 2019

See reply here: #742 (comment) - I think they're the same issue, and I don't think it's fixable

@muglug muglug closed this as completed Jan 6, 2019
@muglug muglug added wontfix and removed wontfix labels Jan 6, 2019
@muglug
Copy link
Collaborator

muglug commented Jan 6, 2019

It's not quite the same issue, actually. Going to reopen, sorry.

@muglug muglug reopened this Jan 6, 2019
@muglug
Copy link
Collaborator

muglug commented Jan 6, 2019

But nevertheless, after a bunch of thought, I don't think this is worth my effort to fix (beautiful as it would be)

@muglug muglug closed this as completed Jan 6, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement hard problems Problems without an obvious easy solution wontfix
Projects
None yet
Development

No branches or pull requests

2 participants