Psalm: RedundantCondition when asserting exception sub-class

Created on 3 Nov 2020  Â·  7Comments  Â·  Source: vimeo/psalm

While creating https://github.com/doctrine/dbal/pull/4401, I noticed that Psalm complains in the following (simplified) case:

class DriverException {}

class ConnectionException extends DriverException {}

interface ExceptionConverter
{
    public function convert(): DriverException;
}

class Test
{
    private ExceptionConverter $converter;

    /**
     * @param class-string<DriverException> $expectedClass
     *
     * @dataProvider exceptionConversionProvider
     */
    public function testConvertsException(string $expectedClass): void
    {
        $dbalException = $this->converter->convert();

        self::assertInstanceOf($expectedClass, $dbalException);
    }

    public function exceptionConversionProvider(): array
    {
        return [
            [ConnectionException::class],
        ];
    }
}

ERROR: RedundantCondition - tests/Driver/API/ExceptionConverterTest.php:54:15 - Type Doctrine\DBAL\Exception\DriverException for $dbalException is always Doctrine\DBAL\Exception\DriverException (see https://psalm.dev/122)
self::assertInstanceOf($expectedClass, $dbalException);

As far as I can see, the condition is not redundant: while $dbalException is a DriverException, there is no guarantee that it passes the instanceof check for the subclass of DriverException provided.

Full reproducer:

git clone https://github.com/BenMorel/dbal.git
cd dbal
git checkout unused-var
composer install
vendor/bin/psalm

Most helpful comment

Actually this is an issue with PHPUnit's assertion – it should be @psalm-assert =T: https://psalm.dev/r/c02c5ac41f

Please open a ticket in PHPUnit's repo!

All 7 comments

Cannot reproduce it on psalm.dev I'm afraid.

Running the above doesn't reproduce the stated issue

Actually here's a simple reproducer: https://psalm.dev/r/6d85680f44

I found these snippets:


https://psalm.dev/r/6d85680f44

<?php declare(strict_types = 1);

/**
 * @param mixed $value
 * @param class-string<T> $type
 * @template T
 * @psalm-assert T $value
 */
function assertInstanceOf($value, string $type): void {
    // some code
}

class E {}

/** @param class-string<E> $e_class */
function foo(string $e_class, E $some_e) : void {
    assertInstanceOf($some_e, $e_class);
}
Psalm output (using commit 5abde20):

ERROR: RedundantCondition - 17:5 - Type E for $some_e is always E

Actually this is an issue with PHPUnit's assertion – it should be @psalm-assert =T: https://psalm.dev/r/c02c5ac41f

Please open a ticket in PHPUnit's repo!

I found these snippets:


https://psalm.dev/r/c02c5ac41f

<?php declare(strict_types = 1);

/**
 * @param mixed $value
 * @param class-string<T> $type
 * @template T
 * @psalm-assert =T $value
 */
function assertInstanceOf($value, string $type): void {
    // some code
}

class E {}

/** @param class-string<E> $e_class */
function foo(string $e_class, E $some_e) : void {
    assertInstanceOf($some_e, $e_class);
}
Psalm output (using commit 5abde20):

No issues!

Thanks a lot, @muglug!

Was this page helpful?
0 / 5 - 0 ratings