Inferred return type not correct when using first-class callable
I found that Psalm (and PHPStan) could not determine the inferred return type correctly when using a First-class Callable. I think it should behave the same as when using a callable via a string. Hopefully the snippet demonstrates the issue🙂
https://psalm.dev/r/b3176fce9b
The expected result is no issues are found.
I found these snippets:
https://psalm.dev/r/b3176fce9b
<?php declare(strict_types = 1);
class HelloWorld
{
/** @var mixed[] */
private array $list = [1, 2, 3];
/** @return int[] */
public function byMethodName(): array
{
return array_filter($this->list, 'is_int');
}
/** @return int[] */
public function byFirstClass(): array
{
return array_filter($this->list, is_int(...));
}
}
Psalm output (using commit 16b24bd):
INFO: MixedReturnTypeCoercion - 17:10 - The type 'array<array-key, mixed>' is more general than the declared return type 'array<array-key, int>' for HelloWorld::byFirstClass
INFO: MixedReturnTypeCoercion - 14:14 - The declared return type 'array<array-key, int>' for HelloWorld::byFirstClass is more specific than the inferred return type 'array<array-key, mixed>'
I run into another problem with first class callable syntax, which seems so related to this that I decided not to create another issue:
https://psalm.dev/r/d0cc7f5046
I think this will be bit of a problem with PHP 8.4 using array_any():
<?php
if (array_any(['foo',1,2,3], is_int(...))) {
// Crash with ArgumentCountError
}
Fatal error: Uncaught ArgumentCountError: is_int() expects exactly 1 argument, 2 given
I found these snippets:
https://psalm.dev/r/d0cc7f5046
<?php
if (array_filter([1,2,3], is_int(...), ARRAY_FILTER_USE_BOTH)) {
// Crash with ArgumentCountError
}
if (array_filter([1,2,3], 'is_int', ARRAY_FILTER_USE_BOTH)) {
// Crash with ArgumentCountError
}
Psalm output (using commit 16b24bd):
ERROR: PossiblyInvalidArgument - 7:27 - Argument 2 of array_filter expects callable(1|2|3, int<0, 2>):mixed, but possibly different type pure-callable(mixed):bool provided