psalm icon indicating copy to clipboard operation
psalm copied to clipboard

Inferred return type not correct when using first-class callable

Open annuh opened this issue 1 year ago • 3 comments

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.

annuh avatar Jul 08 '24 16:07 annuh

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>'

psalm-github-bot[bot] avatar Jul 08 '24 16:07 psalm-github-bot[bot]

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

mpesari avatar Jul 24 '24 12:07 mpesari

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

psalm-github-bot[bot] avatar Jul 24 '24 12:07 psalm-github-bot[bot]