Skip to content

Commit 9e87130

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

4 files changed

Lines changed: 37 additions & 28 deletions

File tree

src/Reflection/InitializerExprTypeResolver.php

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -591,33 +591,37 @@ public function resolveConcatType(Type $left, Type $right): Type
591591
$accessoryTypes[] = new AccessoryUppercaseStringType();
592592
}
593593

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;
599-
600-
$allRightConstantsZeroOrMore = false;
601-
foreach ($rightConstantStrings as $rightConstantString) {
602-
if ($rightConstantString->getValue() === '') {
603-
continue;
604-
}
594+
if ($leftStringType->isDecimalIntegerString()->and($rightStringType->isDecimalIntegerString())->yes()) {
595+
$accessoryTypes[] = new AccessoryUppercaseStringType();
596+
} else {
597+
$leftNumericStringNonEmpty = TypeCombinator::remove($leftStringType, new ConstantStringType(''));
598+
if ($leftNumericStringNonEmpty->isNumericString()->yes()) {
599+
$validationCallback = $left->isInteger()->yes()
600+
? static fn (string $value): bool => !str_starts_with($value, '-')
601+
: static fn (string $value): bool => Strings::match($value, '#^\d+$#') !== null;
605602

606-
if (
607-
!is_numeric($rightConstantString->getValue())
608-
|| !$validationCallback($rightConstantString->getValue())
609-
) {
610-
$allRightConstantsZeroOrMore = false;
611-
break;
612-
}
603+
$allRightConstantsZeroOrMore = false;
604+
foreach ($rightConstantStrings as $rightConstantString) {
605+
if ($rightConstantString->getValue() === '') {
606+
continue;
607+
}
613608

614-
$allRightConstantsZeroOrMore = true;
615-
}
609+
if (
610+
!is_numeric($rightConstantString->getValue())
611+
|| !$validationCallback($rightConstantString->getValue())
612+
) {
613+
$allRightConstantsZeroOrMore = false;
614+
break;
615+
}
616+
617+
$allRightConstantsZeroOrMore = true;
618+
}
616619

617-
$zeroOrMoreInteger = IntegerRangeType::fromInterval(0, null);
618-
$nonNegativeRight = $allRightConstantsZeroOrMore || $zeroOrMoreInteger->isSuperTypeOf($right)->yes();
619-
if ($nonNegativeRight) {
620-
$accessoryTypes[] = new AccessoryNumericStringType();
620+
$zeroOrMoreInteger = IntegerRangeType::fromInterval(0, null);
621+
$nonNegativeRight = $allRightConstantsZeroOrMore || $zeroOrMoreInteger->isSuperTypeOf($right)->yes();
622+
if ($nonNegativeRight) {
623+
$accessoryTypes[] = new AccessoryNumericStringType();
624+
}
621625
}
622626
}
623627

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 & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
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;
1516
use PHPStan\Type\Accessory\AccessoryNumericStringType;
@@ -509,7 +510,7 @@ public function toString(): Type
509510
new StringType(),
510511
new AccessoryLowercaseStringType(),
511512
new AccessoryUppercaseStringType(),
512-
new AccessoryNumericStringType(),
513+
new AccessoryDecimalIntegerStringType(),
513514
new AccessoryNonFalsyStringType(),
514515
]);
515516
}
@@ -518,7 +519,7 @@ public function toString(): Type
518519
new StringType(),
519520
new AccessoryLowercaseStringType(),
520521
new AccessoryUppercaseStringType(),
521-
new AccessoryNumericStringType(),
522+
new AccessoryDecimalIntegerStringType(),
522523
]);
523524
}
524525

src/Type/IntegerType.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
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;
1011
use PHPStan\Type\Accessory\AccessoryNumericStringType;
1112
use PHPStan\Type\Accessory\AccessoryUppercaseStringType;
@@ -78,7 +79,7 @@ public function toString(): Type
7879
new StringType(),
7980
new AccessoryLowercaseStringType(),
8081
new AccessoryUppercaseStringType(),
81-
new AccessoryNumericStringType(),
82+
new AccessoryDecimalIntegerStringType(),
8283
]);
8384
}
8485

0 commit comments

Comments
 (0)