Skip to content

Commit 3db4f49

Browse files
Add more numeric-string inferences after string concat
1 parent cff7b43 commit 3db4f49

File tree

2 files changed

+20
-4
lines changed

2 files changed

+20
-4
lines changed

src/Reflection/InitializerExprTypeResolver.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@
117117
use function max;
118118
use function min;
119119
use function sprintf;
120+
use function str_starts_with;
120121
use function strtolower;
121122
use const INF;
122123

@@ -588,6 +589,10 @@ public function resolveConcatType(Type $left, Type $right): Type
588589

589590
$leftNumericStringNonEmpty = TypeCombinator::remove($leftStringType, new ConstantStringType(''));
590591
if ($leftNumericStringNonEmpty->isNumericString()->yes()) {
592+
$validationCallback = $left->isInteger()->yes()
593+
? static fn (string $value): bool => !str_starts_with($value, '-')
594+
: static fn (string $value): bool => Strings::match($value, '#^\d+$#') !== null;
595+
591596
$allRightConstantsZeroOrMore = false;
592597
foreach ($rightConstantStrings as $rightConstantString) {
593598
if ($rightConstantString->getValue() === '') {
@@ -596,7 +601,7 @@ public function resolveConcatType(Type $left, Type $right): Type
596601

597602
if (
598603
!is_numeric($rightConstantString->getValue())
599-
|| Strings::match($rightConstantString->getValue(), '#^[0-9]+$#') === null
604+
|| !$validationCallback($rightConstantString->getValue())
600605
) {
601606
$allRightConstantsZeroOrMore = false;
602607
break;

tests/PHPStan/Analyser/nsrt/bug-11129.php

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,20 @@ public function foo(
4848
assertType('lowercase-string&non-falsy-string', $i.$maybeNonNumericConstStrings);
4949
assertType('lowercase-string&non-falsy-string', $maybeNonNumericConstStrings.$i);
5050

51-
assertType('lowercase-string&non-falsy-string&uppercase-string', $i.$maybeFloatConstStrings); // could be 'lowercase-string&non-falsy-string&numeric-string'
51+
assertType('lowercase-string&non-falsy-string&numeric-string&uppercase-string', $i.$maybeFloatConstStrings);
5252
assertType('lowercase-string&non-falsy-string&uppercase-string', $maybeFloatConstStrings.$i);
5353

54+
assertType('lowercase-string&non-falsy-string&numeric-string&uppercase-string', $i.'1');
55+
assertType('lowercase-string&non-falsy-string&numeric-string&uppercase-string', $i.'1.0');
56+
assertType('lowercase-string&non-falsy-string&uppercase-string', $i.'1.1.1');
57+
assertType('lowercase-string&non-falsy-string&uppercase-string', $i.'-1');
58+
assertType('lowercase-string&non-falsy-string&uppercase-string', $i.'-1.0');
59+
assertType('lowercase-string&non-falsy-string&numeric-string', $i.'10e-3');
60+
assertType('lowercase-string&non-falsy-string', $i.'-10e-3');
61+
assertType('non-falsy-string&numeric-string&uppercase-string', $i.'10E3');
62+
assertType('non-falsy-string&uppercase-string', $i.'-10E3');
63+
assertType('non-falsy-string', $i.'10eE3');
64+
5465
assertType('lowercase-string&non-empty-string&numeric-string&uppercase-string', $i.$bool);
5566
assertType('lowercase-string&non-empty-string&uppercase-string', $bool.$i);
5667
assertType('lowercase-string&non-falsy-string&numeric-string&uppercase-string', $positiveInt.$bool);
@@ -68,14 +79,14 @@ public function foo(
6879
assertType('non-falsy-string&numeric-string&uppercase-string', $float.$positiveInt);
6980
assertType('non-falsy-string&uppercase-string', $float.$negativeInt);
7081
assertType('non-falsy-string&uppercase-string', $float.$i);
71-
assertType('non-falsy-string&uppercase-string', $i.$float); // could be 'non-falsy-string&numeric-string&uppercase-string'
82+
assertType('non-falsy-string&uppercase-string', $i.$float);
7283
assertType('non-falsy-string', $numericString.$float);
7384
assertType('non-falsy-string', $numericString.$maybeFloatConstStrings);
7485

7586
// https://3v4l.org/Ia4r0
7687
$scientificFloatAsString = '3e4';
7788
assertType('non-falsy-string', $numericString.$scientificFloatAsString);
78-
assertType('lowercase-string&non-falsy-string', $i.$scientificFloatAsString);
89+
assertType('lowercase-string&non-falsy-string&numeric-string', $i.$scientificFloatAsString);
7990
assertType('non-falsy-string', $scientificFloatAsString.$numericString);
8091
assertType('lowercase-string&non-falsy-string', $scientificFloatAsString.$i);
8192
}

0 commit comments

Comments
 (0)