phpstan-phpunit icon indicating copy to clipboard operation
phpstan-phpunit copied to clipboard

assertNotContains appears to be messing something up.

Open doppynl opened this issue 1 month ago • 0 comments

I've got a weird issue that I can't seem to figure out. I think it is a bug in PHPStan, but I'm not certain. I appreciate if you can point me in a way on how to debug this or help you figure out what is wrong.

Some context first:

  • popped up after upgrading PHPStan yesterday, it was not there before. I update very often, so it was a recent change.
  • Happens on both PHP8.4 and PHP8.5alpha
  • It involves the PHPUnit method "assetNotContains", so I don't think I can create a playground example.
  • I tried creating a small repo with an example, but I can't reproduce the error there. I'm not sure why. I used the same phpstan.neon file (just paths changed) and the contents of the classes appear identical to me (except namespaces).

Given this (a bit shortened) test class:

class OmegaTag
{
    /**
     * @var Collection<array-key, OmegaProduct>
     */
    private Collection $products;

    public function __construct()
    {
        $this->products = new ArrayCollection();
    }

    /**
     * @return Collection<array-key, OmegaProduct>
     */
    public function getProducts(): Collection
    {
        return $this->products;
    }
}

This (shortened) test:

    public function testBasic(): void
    {
        $product = new OmegaProduct();
        $tag = new OmegaTag();

        self::assertNotContains($product, $tag->getProducts());
        self::assertCount(0, $tag->getProducts());
    }

This gives me this error:

Call to static method PHPUnit\Framework\Assert::assertCount() with 0 and *NEVER* will always evaluate to false.                                   
🪪  staticMethod.impossibleType

I'm not sure how PHPStan got to the type *NEVER*.

Observations:

  • When I remove the line with the method assertNotContains, the error goes away.
  • When I refactor the 2 $tag->getProducts() calls to a single variable and use that in the test, the error is still there.

It seems that assertNotContains narrows the type to never, while I think it should not do that.

Is there any direction you can point me in to find out what is wrong here? Or is there any more info I can give if you think this is a bug?

doppynl avatar Nov 13 '25 10:11 doppynl