Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions src/Type/Accessory/AccessoryDecimalIntegerStringType.php
Original file line number Diff line number Diff line change
Expand Up @@ -205,14 +205,13 @@ public function unsetOffset(Type $offsetType): Type

public function toNumber(): Type
{
if ($this->inverse) {
return new UnionType([
$this->toInteger(),
$this->toFloat(),
]);
}

return $this->toInteger();
// Decimal integer strings larger than PHP_INT_MAX (or smaller than
// PHP_INT_MIN) overflow to float when coerced to a number, so the
// numeric coercion is int|float even for non-inverse values.
return new UnionType([
$this->toInteger(),
$this->toFloat(),
]);
}

public function toAbsoluteNumber(): Type
Expand Down
38 changes: 38 additions & 0 deletions tests/PHPStan/Analyser/nsrt/bug-14786.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php declare(strict_types = 1);

namespace Bug14786;

use function PHPStan\Testing\assertType;

/** @param decimal-int-string $s */
function unaryPlus(string $s): void
{
// big decimal-int-strings overflow PHP_INT_MAX and become float
assertType('float|int', +$s);
}

/** @param non-decimal-int-string $s */
function unaryPlusNonDecimal(string $s): void
{
assertType('float|int', +$s);
}

/** @param numeric-string $s */
function unaryPlusNumeric(string $s): void
{
assertType('float|int', +$s);
}

/** @param decimal-int-string $s */
function intval(string $s): void
{
// explicit int cast never overflows to float
assertType('int', (int) $s);
}

/** @param decimal-int-string $s */
function arithmetic(string $s): void
{
assertType('float|int', $s + 1);
assertType('float|int', $s * 2);
}
2 changes: 1 addition & 1 deletion tests/PHPStan/Analyser/nsrt/decimal-int-string.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public function doFoo(string $s): void

assertType('bool', (bool) $s);

assertType('int', $s + $s);
assertType('float|int', $s + $s);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1367,4 +1367,10 @@ public function testBug6211(): void
]);
}

public function testBug14786(): void
{
$this->treatPhpDocTypesAsCertain = true;
$this->analyse([__DIR__ . '/data/bug-14786.php'], []);
}

}
17 changes: 17 additions & 0 deletions tests/PHPStan/Rules/Comparison/data/bug-14786.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php declare(strict_types = 1);

namespace Bug14786;

// example inspired by nikic/PHP-Parser ParserAbstract::parseNumber()
/** @param decimal-int-string $str */
function parseNumber(string $str): int|float
{
// big decimal-int-strings overflow PHP_INT_MAX and become float,
// so is_int() is no longer always true.
$num = +$str;
if (!is_int($num)) {
return $num;
}

return $num;
}
Loading