php-standard-library / psalm-plugin

Psalm integration for the PHP Standard Library
MIT License
24 stars 6 forks source link

Incorrectly inferred return type for `Psl\Iter\first(...)` #12

Open evang522 opened 1 year ago

evang522 commented 1 year ago

Describe the bug When provided an array with type list<string>, the output of Psl\Iter\first($array) is considered by the plugin's FunctionReturnTypeProvider to be never null, which is presumably not true.

To Reproduce

Run Psalm with this plugin enabled on the following code:

/** @var list<string> $series  **/
$series = ['val1', 'val2'];

$firstInSeries = \Psl\Iter\first($series);

\assert($firstInSeries !== null); // assert with any assertion module you like, it's a similar output for all.

Output:

ERROR: RedundantConditionGivenDocblockType - ../../test.php:32:9 - Docblock-defined type string can never contain null (see https://psalm.dev/156)
\assert($firstInSeries !== null);

When duplicating the code of \Psl\Iter\first so that the plugin is not applied, this problem does not occur:

/**
 * @template T
 *
 * @param iterable<T> $iterable
 *
 * @return T|null
 */
function first(iterable $iterable)
{
    foreach ($iterable as $v) {
        return $v;
    }

    return null;
}

/** @var list<string> $series  **/
$series = ['val1', 'val2'];

$firstInSeries = first($series);

\assert($firstInSeries !== null);

Output: No errors found!

Expected behavior \Psl\Iter\first return type is considered to be possibly null as long as the array is not non-empty-list<*>

Environment (please complete the following information):

Thanks a lot!

azjezz commented 1 year ago

this shouldn't really happen unless the type is known not to be empty ( https://github.com/php-standard-library/psalm-plugin/blob/main/src/EventHandler/Iter/First/FunctionReturnTypeProvider.php#L36-L42 ), i will look further into it 👍