-
-
Notifications
You must be signed in to change notification settings - Fork 942
Description
Bug report
This one has me stumped after trying many different variants of the PHPDoc tags on throwOnFailure(). As best I can tell, PHPStan is widening the incoming type from <something>|false to <something>|bool, which it then narrows to <something>|true per the conditional return type.
<?php declare(strict_types=1);
class A
{
private int $Counter = 0;
/**
* @return stdClass
*/
public function getMayFail()
{
// PHPStan reports "Method A::getMayFail() should return stdClass but returns stdClass|true."
return $this->throwOnFailure($this->mayFail());
}
/**
* @template T
*
* @param T $result
* @return (T is false ? never : T)
*/
public function throwOnFailure($result)
{
if ($result === false) {
throw new Exception('Operation failed');
}
return $result;
}
/**
* @return stdClass|false
*/
public function mayFail()
{
$this->Counter++;
return $this->Counter % 2 ? new stdClass() : false;
}
}If I change the DocBlock to this, it works:
/**
* @template T
*
* @param T|false $result
* @return ($result is false ? never : T)
*/...but other tools (Intelephense, at least) don't like it and it isn't amenable to adding a second template for the failure value (e.g. so the caller can specify whether false or -1 are regarded as failures); and the original syntax should work 😉
Code snippet that reproduces the problem
https://phpstan.org/r/06424f05-e1f9-4d72-903b-0f2cc1cc183b
Expected output
No errors; types should narrow to exclude false without adding true.
Did PHPStan help you today? Did it make you happy in any way?
In this moment it isn't making me happy 🤣 But I'm finally leveling up to 9 across my projects and am appreciating the quality improvements ❤️