-
Notifications
You must be signed in to change notification settings - Fork 584
Negating the smallest integer results in a float #6029
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| <?php | ||
|
|
||
| namespace Abs64bit; | ||
|
|
||
| use function PHPStan\Testing\assertType; | ||
|
|
||
| // abs() of the smallest integer overflows and returns a float. | ||
| assertType('9.223372036854776E+18', abs(-9223372036854775807 - 1)); | ||
| assertType('2147483648|9.223372036854776E+18', abs(PHP_INT_MIN)); | ||
|
|
||
| // One step away from the overflow, so still an integer. | ||
| assertType('9223372036854775807', abs(-9223372036854775807)); | ||
| assertType('2147483647|9223372036854775807', abs(-PHP_INT_MAX)); | ||
|
|
||
| function integerRanges(int $int): void | ||
| { | ||
| /** @var int<-9223372036854775808, 0> $int */ | ||
| assertType('int<0, max>', abs($int)); | ||
|
|
||
| /** @var int<-9223372036854775808, -1> $int */ | ||
| assertType('int<1, max>', abs($int)); | ||
|
|
||
| /** @var int<-9223372036854775808, 9223372036854775807> $int */ | ||
| assertType('int<0, max>', abs($int)); | ||
|
|
||
| // The only value in this range is the smallest integer. | ||
| /** @var int<min, -9223372036854775808> $int */ | ||
| assertType('9.223372036854776E+18', abs($int)); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| <?php | ||
|
|
||
| namespace UnaryMinus64bit; | ||
|
|
||
| use function PHPStan\Testing\assertType; | ||
|
|
||
| // Negating the smallest integer overflows and produces a float. | ||
| assertType('9.223372036854776E+18', -(-9223372036854775807 - 1)); | ||
| assertType('2147483648|9.223372036854776E+18', -PHP_INT_MIN); | ||
|
staabm marked this conversation as resolved.
|
||
|
|
||
| // Negating the largest integer stays an integer. | ||
| assertType('-9223372036854775807|-2147483647', -PHP_INT_MAX); | ||
|
|
||
| $min = -9223372036854775807 - 1; | ||
| assertType('9.223372036854776E+18', -$min); | ||
|
|
||
| assertType('9223372036854775807', -(-9223372036854775807)); | ||
| assertType('-9223372036854775807', -9223372036854775807); | ||
|
|
||
| function integerRanges(int $int): void | ||
| { | ||
| /** @var int<min, -1> $int */ | ||
| assertType('int<1, max>', -$int); | ||
|
|
||
| /** @var int<-9223372036854775808, -1> $int */ | ||
| assertType('int<1, max>', -$int); | ||
| } | ||
|
|
||
| function constantUnion(int $int): void | ||
| { | ||
| /** @var -1|-2 $int */ | ||
| assertType('1|2', -$int); | ||
|
Comment on lines
+31
to
+32
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should test another union constant type, like
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good call. function constantUnion(int $int): void
{
/** @var 9223372036854775807|25 $int */
assertType('-9223372036854775807|-25', -$int);
}
// The union has one member that overflows and one that does not.
function partiallyOverflowingUnion(bool $bool): void
{
$int = $bool ? -9223372036854775807 - 1 : 25;
assertType('-9223372036854775808|25', $int);
assertType('-25|9.223372036854776E+18', -$int);
}Before this PR the last one inferred I had to build the union with a ternary rather than a PHPDoc type: Both in fcff019. |
||
|
|
||
| /** @var 9223372036854775807|25 $int */ | ||
| assertType('-9223372036854775807|-25', -$int); | ||
| } | ||
|
|
||
| // The union has one member that overflows and one that does not. | ||
| function partiallyOverflowingUnion(bool $bool): void | ||
| { | ||
| $int = $bool ? -9223372036854775807 - 1 : 25; | ||
| assertType('-9223372036854775808|25', $int); | ||
| assertType('-25|9.223372036854776E+18', -$int); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if it wouldn't be better to have such logic in fromInterval instead ?
Like int<min, PHP_INT_MIN> is constantInteger(PHP_INT_MIN)
And int<PHP_INT_MAX, max> is constantInteger(PHP_INT_MAX)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great suggestion, done in 17eef36.
It runs after
shift()so thatcreateAllSmallerThan(PHP_INT_MIN)keeps returningNeverTyperather than collapsing toPHP_INT_MIN.With that,
toAbsoluteNumber()loses itsmax === PHP_INT_MINspecial case, since noIntegerRangeTypecan hold that bound any more. The remaining guard is formin === PHP_INT_MINon a range that holds more than one value, where negating the bound still overflows.fromInterval()could normalize that bound tonulltoo, sinceint<-9223372036854775808, 0>andint<min, 0>denote the same values, but it would change how those types describe themselves (random_int(PHP_INT_MIN, PHP_INT_MAX)would go fromint<-9223372036854775808, 9223372036854775807>toint). Happy to do it if you want, though it feels like a separate change.Everything moved to #6028, this PR is closed.