Skip to content

Commit 6153259

Browse files
Improve decimal integer string inferences
1 parent 2f2bd5c commit 6153259

File tree

4 files changed

+41
-29
lines changed

4 files changed

+41
-29
lines changed

src/Reflection/InitializerExprTypeResolver.php

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
use PHPStan\ShouldNotHappenException;
4646
use PHPStan\TrinaryLogic;
4747
use PHPStan\Type\Accessory\AccessoryArrayListType;
48+
use PHPStan\Type\Accessory\AccessoryDecimalIntegerStringType;
4849
use PHPStan\Type\Accessory\AccessoryLiteralStringType;
4950
use PHPStan\Type\Accessory\AccessoryLowercaseStringType;
5051
use PHPStan\Type\Accessory\AccessoryNonEmptyStringType;
@@ -591,33 +592,41 @@ public function resolveConcatType(Type $left, Type $right): Type
591592
$accessoryTypes[] = new AccessoryUppercaseStringType();
592593
}
593594

594-
$leftNumericStringNonEmpty = TypeCombinator::remove($leftStringType, new ConstantStringType(''));
595-
if ($leftNumericStringNonEmpty->isNumericString()->yes()) {
596-
$validationCallback = $left->isInteger()->yes()
597-
? static fn (string $value): bool => !str_starts_with($value, '-')
598-
: static fn (string $value): bool => Strings::match($value, '#^\d+$#') !== null;
595+
$leftStringNonEmpty = TypeCombinator::remove($leftStringType, new ConstantStringType(''));
596+
$rightStringNonEmpty = TypeCombinator::remove($leftStringType, new ConstantStringType(''));
597+
if (
598+
$leftStringNonEmpty->isDecimalIntegerString()->and($rightStringNonEmpty->isDecimalIntegerString())->yes()
599+
&& $leftStringNonEmpty->isSuperTypeOf(new ConstantStringType('0'))->no()
600+
) {
601+
$accessoryTypes[] = new AccessoryDecimalIntegerStringType();
602+
} else {
603+
if ($leftStringNonEmpty->isNumericString()->yes()) {
604+
$validationCallback = $left->isInteger()->yes()
605+
? static fn (string $value): bool => !str_starts_with($value, '-')
606+
: static fn (string $value): bool => Strings::match($value, '#^\d+$#') !== null;
599607

600-
$allRightConstantsZeroOrMore = false;
601-
foreach ($rightConstantStrings as $rightConstantString) {
602-
if ($rightConstantString->getValue() === '') {
603-
continue;
604-
}
608+
$allRightConstantsZeroOrMore = false;
609+
foreach ($rightConstantStrings as $rightConstantString) {
610+
if ($rightConstantString->getValue() === '') {
611+
continue;
612+
}
605613

606-
if (
607-
!is_numeric($rightConstantString->getValue())
608-
|| !$validationCallback($rightConstantString->getValue())
609-
) {
610-
$allRightConstantsZeroOrMore = false;
611-
break;
612-
}
614+
if (
615+
!is_numeric($rightConstantString->getValue())
616+
|| !$validationCallback($rightConstantString->getValue())
617+
) {
618+
$allRightConstantsZeroOrMore = false;
619+
break;
620+
}
613621

614-
$allRightConstantsZeroOrMore = true;
615-
}
622+
$allRightConstantsZeroOrMore = true;
623+
}
616624

617-
$zeroOrMoreInteger = IntegerRangeType::fromInterval(0, null);
618-
$nonNegativeRight = $allRightConstantsZeroOrMore || $zeroOrMoreInteger->isSuperTypeOf($right)->yes();
619-
if ($nonNegativeRight) {
620-
$accessoryTypes[] = new AccessoryNumericStringType();
625+
$zeroOrMoreInteger = IntegerRangeType::fromInterval(0, null);
626+
$nonNegativeRight = $allRightConstantsZeroOrMore || $zeroOrMoreInteger->isSuperTypeOf($right)->yes();
627+
if ($nonNegativeRight) {
628+
$accessoryTypes[] = new AccessoryNumericStringType();
629+
}
621630
}
622631
}
623632

src/Type/Constant/ConstantStringType.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use PHPStan\Reflection\TrivialParametersAcceptor;
2020
use PHPStan\ShouldNotHappenException;
2121
use PHPStan\TrinaryLogic;
22+
use PHPStan\Type\Accessory\AccessoryDecimalIntegerStringType;
2223
use PHPStan\Type\Accessory\AccessoryLiteralStringType;
2324
use PHPStan\Type\Accessory\AccessoryLowercaseStringType;
2425
use PHPStan\Type\Accessory\AccessoryNonEmptyStringType;
@@ -459,7 +460,9 @@ public function generalize(GeneralizePrecision $precision): Type
459460
new AccessoryLiteralStringType(),
460461
];
461462

462-
if (is_numeric($this->getValue())) {
463+
if ((string) (int) $this->getValue() === $this->getValue()) {
464+
$accessories[] = new AccessoryDecimalIntegerStringType();
465+
} elseif (is_numeric($this->getValue())) {
463466
$accessories[] = new AccessoryNumericStringType();
464467
}
465468

src/Type/IntegerRangeType.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
1111
use PHPStan\Reflection\InitializerExprTypeResolver;
1212
use PHPStan\TrinaryLogic;
13+
use PHPStan\Type\Accessory\AccessoryDecimalIntegerStringType;
1314
use PHPStan\Type\Accessory\AccessoryLowercaseStringType;
1415
use PHPStan\Type\Accessory\AccessoryNonFalsyStringType;
15-
use PHPStan\Type\Accessory\AccessoryNumericStringType;
1616
use PHPStan\Type\Accessory\AccessoryUppercaseStringType;
1717
use PHPStan\Type\Constant\ConstantBooleanType;
1818
use PHPStan\Type\Constant\ConstantIntegerType;
@@ -509,7 +509,7 @@ public function toString(): Type
509509
new StringType(),
510510
new AccessoryLowercaseStringType(),
511511
new AccessoryUppercaseStringType(),
512-
new AccessoryNumericStringType(),
512+
new AccessoryDecimalIntegerStringType(),
513513
new AccessoryNonFalsyStringType(),
514514
]);
515515
}
@@ -518,7 +518,7 @@ public function toString(): Type
518518
new StringType(),
519519
new AccessoryLowercaseStringType(),
520520
new AccessoryUppercaseStringType(),
521-
new AccessoryNumericStringType(),
521+
new AccessoryDecimalIntegerStringType(),
522522
]);
523523
}
524524

src/Type/IntegerType.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
77
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
88
use PHPStan\TrinaryLogic;
9+
use PHPStan\Type\Accessory\AccessoryDecimalIntegerStringType;
910
use PHPStan\Type\Accessory\AccessoryLowercaseStringType;
10-
use PHPStan\Type\Accessory\AccessoryNumericStringType;
1111
use PHPStan\Type\Accessory\AccessoryUppercaseStringType;
1212
use PHPStan\Type\Constant\ConstantArrayType;
1313
use PHPStan\Type\Constant\ConstantBooleanType;
@@ -78,7 +78,7 @@ public function toString(): Type
7878
new StringType(),
7979
new AccessoryLowercaseStringType(),
8080
new AccessoryUppercaseStringType(),
81-
new AccessoryNumericStringType(),
81+
new AccessoryDecimalIntegerStringType(),
8282
]);
8383
}
8484

0 commit comments

Comments
 (0)