vimeo / psalm

A static analysis tool for finding errors in PHP applications
https://psalm.dev
MIT License
5.57k stars 660 forks source link

Failing indirect type import #11115

Open jnvsor opened 1 month ago

jnvsor commented 1 month ago

When using an imported type in @psalm-assert-if-true a third-party consumer doesn't get the type correctly and I can't reproduce it in the sandbox or in separate files.

The type TraceFrame is defined as:

/**
 * @psalm-type TraceFrame array{
 *   function: string,
 *   line?: int,
 *   file?: string,
 *   class?: class-string,
 *   object?: object,
 *   type?: string,
 *   args?: list<mixed>
 * }
 */

And imported and used in:

/**
 * @psalm-import-type TraceFrame from TraceFrameValue
 */
final class Utils
{
    /**
     * @psalm-assert-if-true list<TraceFrame> $trace
     */
    public static function isTrace(array $trace): bool
    {
        ...

Then when this is used in another piece of code the type is traced as list<type-alias(Kint\Zval\TraceFrameValue::TraceFrame)> and causes errors.

The full code can be viewed in jnvsor/kint@5f5e69d2c28e821221ee5e60b16f7541feb1fce0

Please ignore the deluge of errors, it's a refactor in progress... The relevant traces and errors are below:

ERROR: Trace - src/Parser/TracePlugin.php:100:13 - $trace: list<type-alias(Kint\Zval\TraceFrameValue::TraceFrame)> (see https://psalm.dev/224)
            /**
             * @psalm-trace $trace
             * @psalm-trace $index
             * @psalm-trace $trace[$index]
             */
            if (!isset($trace[$index]['file'])) {
                continue;
            }

ERROR: Trace - src/Parser/TracePlugin.php:100:13 - $index: int|string (see https://psalm.dev/224)
            /**
             * @psalm-trace $trace
             * @psalm-trace $index
             * @psalm-trace $trace[$index]
             */
            if (!isset($trace[$index]['file'])) {
                continue;
            }

ERROR: Trace - src/Parser/TracePlugin.php:100:13 - $trace[$index]: mixed (see https://psalm.dev/224)
            /**
             * @psalm-trace $trace
             * @psalm-trace $index
             * @psalm-trace $trace[$index]
             */
            if (!isset($trace[$index]['file'])) {
                continue;
            }

ERROR: InvalidArrayAccess - src/Parser/TracePlugin.php:100:24 - Cannot access array value on non-array variable $trace[$index] of type type-alias(Kint\Zval\TraceFrameValue::TraceFrame) (see https://psalm.dev/005)
            if (!isset($trace[$index]['file'])) {

Even if $trace[$index] is a non-existent index (Which should be a different error) it should be null|TraceFrame not mixed as in the trace, and the actual error doesn't recognise that the type-alias(...) is an array

psalm-github-bot[bot] commented 1 month ago

Hey @jnvsor, can you reproduce the issue on https://psalm.dev? These will be used as phpunit tests when implementing the feature or fixing this bug.