psalm icon indicating copy to clipboard operation
psalm copied to clipboard

array_find return value seems to be broken in 6.8.0

Open Daeroni opened this issue 10 months ago • 8 comments

When upgrading to 6.8.0 I noticed that array_fid return value seems to be broken, defaulting to mixed instead of deducing it from the input array

https://psalm.dev/r/1ad7073d07

Psalm output (using commit [9ae98ac](https://github.com/vimeo/psalm/commit/9ae98ac) on PHP 8.2.27): 

INFO: [Trace](https://psalm.dev/224) - 22:5 - $accounts: list<Account>

INFO: [MixedAssignment](https://psalm.dev/032) - 25:2 - Unable to determine the type that $account is being assigned to

INFO: [Trace](https://psalm.dev/224) - 25:2 - $account: mixed

INFO: [MixedReturnStatement](https://psalm.dev/138) - 34:12 - Could not infer a return type

Expected output (on psalm 6.7.1):

INFO: [Trace](https://psalm.dev/224) - 22:5 - $accounts: list<Account>

INFO: [Trace](https://psalm.dev/224) - 25:2 - $account: Account|null

Daeroni avatar Feb 24 '25 14:02 Daeroni

I found these snippets:

https://psalm.dev/r/1ad7073d07
<?php

class Account {
    public function __construct(
	    public string $iban,
    ) {}
}

/**
 * @return list<Account>
 */
function getAccounts(): array {
    return [
    	new Account('abc'),
    	new Account('def'),
    	new Account('ghi'),
    ];
}
    
function getAccountByIban(string $iban): Account {
    /** @psalm-trace $accounts */
    $accounts = getAccounts();
    
    /** @psalm-trace $account */
	$account = array_find(
        $accounts,
        fn (Account $account) => $account->iban === $iban
    );
        
    if ($account === null) {
        throw new Exception;
    }

    return $account;
}
Psalm output (using commit 9ae98ac):

INFO: Trace - 22:5 - $accounts: list<Account>

INFO: MixedAssignment - 25:2 - Unable to determine the type that $account is being assigned to

INFO: Trace - 25:2 - $account: mixed

INFO: MixedReturnStatement - 34:12 - Could not infer a return type

psalm-github-bot[bot] avatar Feb 24 '25 14:02 psalm-github-bot[bot]

Disregard this, It seems we had a following stub:

/**
 * Use template for better DX.
 *
 * @psalm-pure Ignore impurity
 *
 * @template K of array-key
 * @template V
 *
 * @param array<K,V> $array
 * @param Closure(V,K):bool $callback
 *
 * @return V|null
 */
function array_find(array $array, callable $callback): mixed {}

Which produced the expected output, however, psalm 6.8.0 broke the stub

Daeroni avatar Feb 24 '25 15:02 Daeroni

Seems fixed in 6.8.7

orklah avatar Feb 26 '25 16:02 orklah

Not fixed, needs more work adapting the array_filter return type provider

danog avatar Feb 26 '25 16:02 danog

A repro of the issue: https://psalm.dev/r/0caf23f641

djmetzle avatar Jun 02 '25 22:06 djmetzle

I found these snippets:

https://psalm.dev/r/0caf23f641
<?php

$a = ['a' => 1, 'b' => 2, 'c' => 3];

/** @psalm-trace $_x */
$_x = array_find($a, fn ($n) => $n === 2);

/** @psalm-trace $_y */
$_y = array_find($a, fn (int $value, string $_key): bool => $value === 2);

$find = function(int $value, string $_key): bool {
	return $value === 3;
};
/** @psalm-trace $_z */
$_z = array_find($a, $find);
Psalm output (using commit 6670889):

INFO: Trace - 6:1 - $_x: mixed

INFO: Trace - 9:1 - $_y: mixed

INFO: Trace - 15:1 - $_z: mixed

psalm-github-bot[bot] avatar Jun 02 '25 22:06 psalm-github-bot[bot]