Bug report
Analysing abs(PHP_INT_MIN) crashes with an internal error:
Internal error: PHPStan\Type\Constant\ConstantIntegerType::__construct():
Argument #1 ($value) must be of type int, float given,
called in src/Type/Constant/ConstantIntegerType.php on line 88
ConstantIntegerType::toAbsoluteNumber() does new self(abs($this->value)), but PHP's abs(PHP_INT_MIN) returns a float, because -PHP_INT_MIN is not representable as an int:
var_dump(abs(PHP_INT_MIN)); // float(9.2233720368548E+18)
Note that abs(-9223372036854775808) on the second line of the playground link does not crash — that literal is already a float, so it takes a different code path.
IntegerRangeType::toAbsoluteNumber() has the same problem in two places ($this->min * -1 and $this->max * -1), so these crash too:
/** @var int<-9223372036854775808, 0> $a */
abs($a); // Internal error: IntegerRangeType::fromInterval(): Argument #2 ($max) must be of type ?int, float given
/** @var int<-9223372036854775808, -1> $b */
abs($b); // same
/** @var int<min, -9223372036854775808> $c */
abs($c); // Internal error: ... Argument #1 ($min) ...
Code snippet that reproduces the problem
https://phpstan.org/r/fa1c992f-684d-4abd-a6fc-b248b18180c6
Expected output
No internal error. abs(PHP_INT_MIN) should be inferred as a float:
\PHPStan\dumpType(abs(-9223372036854775807 - 1)); // 9.223372036854776E+18
For integer ranges, I would expect the existing approximation to be kept, so that a lower bound of PHP_INT_MIN behaves like an unbounded one (abs(int) is already int<0, max> today, and abs(int<min, 0>) is already int<0, max>):
/** @var int<-9223372036854775808, 0> $a */
\PHPStan\dumpType(abs($a)); // int<0, max>
/** @var int<-9223372036854775808, -1> $b */
\PHPStan\dumpType(abs($b)); // int<1, max>
int<min, -9223372036854775808> holds exactly one value, so abs() of it is that same float.
I have a fix ready and will open a PR right away.
Did PHPStan help you today? Did it make you happy in any way?
Yes — I found this while investigating how PHPStan models integer width, and PHPStan's own error messages pointed me straight at the offending line.
Bug report
Analysing
abs(PHP_INT_MIN)crashes with an internal error:ConstantIntegerType::toAbsoluteNumber()doesnew self(abs($this->value)), but PHP'sabs(PHP_INT_MIN)returns afloat, because-PHP_INT_MINis not representable as anint:Note that
abs(-9223372036854775808)on the second line of the playground link does not crash — that literal is already afloat, so it takes a different code path.IntegerRangeType::toAbsoluteNumber()has the same problem in two places ($this->min * -1and$this->max * -1), so these crash too:Code snippet that reproduces the problem
https://phpstan.org/r/fa1c992f-684d-4abd-a6fc-b248b18180c6
Expected output
No internal error.
abs(PHP_INT_MIN)should be inferred as a float:For integer ranges, I would expect the existing approximation to be kept, so that a lower bound of
PHP_INT_MINbehaves like an unbounded one (abs(int)is alreadyint<0, max>today, andabs(int<min, 0>)is alreadyint<0, max>):int<min, -9223372036854775808>holds exactly one value, soabs()of it is that same float.I have a fix ready and will open a PR right away.
Did PHPStan help you today? Did it make you happy in any way?
Yes — I found this while investigating how PHPStan models integer width, and PHPStan's own error messages pointed me straight at the offending line.