psalm icon indicating copy to clipboard operation
psalm copied to clipboard

Wrong returntype "never" for generator function with endless loop

Open UlrichEckhardt opened this issue 1 year ago • 3 comments

Heya!

Check out this example code, in particular the complaint about the return value of the events() function. This function is actually a generator running in an endless loop, the only way out is with an exception. It seems that this combination (endless loop and exception) confuses Psalm enough to flag this as an error. If I just remove the check $events === false and the exception, the complaint about the return value goes away. It still complains about other things then, but those are actual flaws in the code or that Psalm online doesn't recognize the IN_* constants.

I have honestly no idea how to fix this, so I'm relying on your help here.

Regards

Uli

UlrichEckhardt avatar Feb 02 '24 09:02 UlrichEckhardt

I found these snippets:

https://psalm.dev/r/b2075861de
<?php

declare(strict_types=1);

/**
 * @param resource $inotify 
 * @return Generator<array>
 */
function events($inotify): Generator
{
    while (true) {
        $events = inotify_read($inotify);
        if ($events === false) {
            throw new Exception('inotify_read() failed');
        }
        foreach ($events as $event) {
            yield $event;
        }
    }
}

$inotify = inotify_init();
inotify_add_watch($inotify, __DIR__, IN_ALL_EVENTS);
foreach (events($inotify) as $event) {
    echo json_encode($event, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . PHP_EOL;
}
Psalm output (using commit bf57d59):

INFO: MixedAssignment - 16:29 - Unable to determine the type that $event is being assigned to

ERROR: InvalidReturnType - 7:12 - The declared return type 'Generator<mixed, array<array-key, mixed>, mixed, mixed>' for events is incorrect, got 'never'

ERROR: UndefinedConstant - 23:38 - Const IN_ALL_EVENTS is not defined

INFO: MixedArgument - 23:38 - Argument 3 of inotify_add_watch cannot be mixed, expecting int

ERROR: UnusedFunctionCall - 23:1 - The call to inotify_add_watch is not used

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

Simplified: https://psalm.dev/r/a6fea04924

weirdan avatar Feb 03 '24 23:02 weirdan

I found these snippets:

https://psalm.dev/r/a6fea04924
<?php

declare(strict_types=1);

/**
 * @return Generator<int>
 */
function ints(): Generator
{
    while (true) {
        if (rand(0, 1)) {
            throw new Exception;
        }
        yield 1;
    }
}

foreach (ints() as $int) {
    echo $int;
}
Psalm output (using commit bf57d59):

ERROR: InvalidReturnType - 6:12 - The declared return type 'Generator<mixed, int, mixed, mixed>' for ints is incorrect, got 'never'

psalm-github-bot[bot] avatar Feb 03 '24 23:02 psalm-github-bot[bot]