Skip to content

Commit cdd76d2

Browse files
authored
Infer decimal-int-string when casting int/int<a, b> to string (#5794)
1 parent 15c788b commit cdd76d2

19 files changed

Lines changed: 90 additions & 63 deletions

‎src/Type/IntegerRangeType.php‎

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,8 @@
1010
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
1111
use PHPStan\Reflection\InitializerExprTypeResolver;
1212
use PHPStan\TrinaryLogic;
13-
use PHPStan\Type\Accessory\AccessoryLowercaseStringType;
13+
use PHPStan\Type\Accessory\AccessoryDecimalIntegerStringType;
1414
use PHPStan\Type\Accessory\AccessoryNonFalsyStringType;
15-
use PHPStan\Type\Accessory\AccessoryNumericStringType;
16-
use PHPStan\Type\Accessory\AccessoryUppercaseStringType;
1715
use PHPStan\Type\Constant\ConstantBooleanType;
1816
use PHPStan\Type\Constant\ConstantIntegerType;
1917
use function array_filter;
@@ -507,18 +505,14 @@ public function toString(): Type
507505
if ($isZero->no()) {
508506
return new IntersectionType([
509507
new StringType(),
510-
new AccessoryLowercaseStringType(),
511-
new AccessoryUppercaseStringType(),
512-
new AccessoryNumericStringType(),
508+
new AccessoryDecimalIntegerStringType(),
513509
new AccessoryNonFalsyStringType(),
514510
]);
515511
}
516512

517513
return new IntersectionType([
518514
new StringType(),
519-
new AccessoryLowercaseStringType(),
520-
new AccessoryUppercaseStringType(),
521-
new AccessoryNumericStringType(),
515+
new AccessoryDecimalIntegerStringType(),
522516
]);
523517
}
524518

‎src/Type/IntegerType.php‎

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +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\AccessoryLowercaseStringType;
10-
use PHPStan\Type\Accessory\AccessoryNumericStringType;
11-
use PHPStan\Type\Accessory\AccessoryUppercaseStringType;
9+
use PHPStan\Type\Accessory\AccessoryDecimalIntegerStringType;
1210
use PHPStan\Type\Constant\ConstantArrayType;
1311
use PHPStan\Type\Constant\ConstantBooleanType;
1412
use PHPStan\Type\Constant\ConstantIntegerType;
@@ -81,9 +79,7 @@ public function toString(): Type
8179
{
8280
return new IntersectionType([
8381
new StringType(),
84-
new AccessoryLowercaseStringType(),
85-
new AccessoryUppercaseStringType(),
86-
new AccessoryNumericStringType(),
82+
new AccessoryDecimalIntegerStringType(),
8783
]);
8884
}
8985

‎tests/PHPStan/Analyser/nsrt/array-key-exists.php‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,16 @@ public function doBar(array $a, array $b, array $c, int $key1, string $key2, int
5050
assertType('int', $key1);
5151
}
5252
if (array_key_exists($key2, $a)) {
53-
assertType('lowercase-string&numeric-string&uppercase-string', $key2);
53+
assertType('decimal-int-string', $key2);
5454
}
5555
if (array_key_exists($key3, $a)) {
56-
assertType('int|(lowercase-string&numeric-string&uppercase-string)', $key3);
56+
assertType('int|decimal-int-string', $key3);
5757
}
5858
if (array_key_exists($key4, $a)) {
59-
assertType('(int|(lowercase-string&numeric-string&uppercase-string))', $key4);
59+
assertType('(int|decimal-int-string)', $key4);
6060
}
6161
if (array_key_exists($key5, $a)) {
62-
assertType('int|(lowercase-string&numeric-string&uppercase-string)', $key5);
62+
assertType('int|decimal-int-string', $key5);
6363
}
6464

6565
if (array_key_exists($key1, $b)) {

‎tests/PHPStan/Analyser/nsrt/bug-11716.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ function narrowKey($mixed, string $s, int $i, array $generalArr, array $intKeyed
7575
assertType('int', $i);
7676

7777
if (isset($intKeyedArr[$s])) {
78-
assertType("lowercase-string&numeric-string&uppercase-string", $s);
78+
assertType('decimal-int-string', $s);
7979
} else {
8080
assertType('string', $s);
8181
}

‎tests/PHPStan/Analyser/nsrt/bug-12393b.php‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ class FooIntString
343343
public function doFoo(int $b): void
344344
{
345345
$this->foo = $b;
346-
assertType('lowercase-string&numeric-string&uppercase-string', $this->foo);
346+
assertType('decimal-int-string', $this->foo);
347347
}
348348

349349
public function doBar(): void
@@ -418,7 +418,7 @@ class FooNullableIntString
418418
public function doFoo(?int $b): void
419419
{
420420
$this->foo = $b;
421-
assertType('lowercase-string&numeric-string&uppercase-string', $this->foo);
421+
assertType('decimal-int-string', $this->foo);
422422
}
423423

424424
public function doBar(): void

‎tests/PHPStan/Analyser/nsrt/bug-14525.php‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ function arrayWalkGeneric(): void
2020
array_walk($array, function (&$value, $key): void {
2121
$value = (string) $value;
2222
});
23-
assertType("array<string, lowercase-string&numeric-string&uppercase-string>", $array);
23+
assertType('array<string, decimal-int-string>', $array);
2424
}
2525

2626
function arrayWalkNoModification(): void
@@ -63,7 +63,7 @@ function arrayWalkNonEmptyArray(): void
6363
array_walk($array, function (&$value): void {
6464
$value = (string) $value;
6565
});
66-
assertType("non-empty-array<string, lowercase-string&numeric-string&uppercase-string>", $array);
66+
assertType('non-empty-array<string, decimal-int-string>', $array);
6767
}
6868

6969
function arrayWalkList(): void
@@ -73,7 +73,7 @@ function arrayWalkList(): void
7373
array_walk($list, function (&$value): void {
7474
$value = (string) $value;
7575
});
76-
assertType("list<lowercase-string&numeric-string&uppercase-string>", $list);
76+
assertType('list<decimal-int-string>', $list);
7777
}
7878

7979
function arrayWalkAlwaysTerminating(): void
@@ -84,7 +84,7 @@ function arrayWalkAlwaysTerminating(): void
8484
$value = (string) $value;
8585
return;
8686
});
87-
assertType("array<string, lowercase-string&numeric-string&uppercase-string>", $array);
87+
assertType('array<string, decimal-int-string>', $array);
8888
}
8989

9090
function arrayWalkNestedArray(): void
@@ -106,7 +106,7 @@ function arrayWalkWithNestedClosure(): void
106106
}, [1, 2, 3]);
107107
$value = (string) $value;
108108
});
109-
assertType("array<string, lowercase-string&numeric-string&uppercase-string>", $array);
109+
assertType('array<string, decimal-int-string>', $array);
110110
}
111111

112112
function arrayWalkWithNestedClosureByRef(): void
@@ -121,5 +121,5 @@ function arrayWalkWithNestedClosureByRef(): void
121121
$fn();
122122
$value = (string) $value;
123123
});
124-
assertType("array<string, lowercase-string&numeric-string&uppercase-string>", $array);
124+
assertType('array<string, decimal-int-string>', $array);
125125
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Bug14753;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class HelloWorld
8+
{
9+
/**
10+
* @param int<500, max> $positive
11+
* @param int<min, -500> $negative
12+
* @param int<-10, 10> $withZero
13+
* @param int<0, max> $nonNegative
14+
*/
15+
public function sayHello(
16+
int $int,
17+
int $positive,
18+
int $negative,
19+
int $withZero,
20+
int $nonNegative,
21+
bool $bool,
22+
): void
23+
{
24+
assertType('decimal-int-string', (string) $int);
25+
assertType('decimal-int-string&non-falsy-string', (string) $positive);
26+
assertType('decimal-int-string&non-falsy-string', (string) $negative);
27+
assertType('decimal-int-string', (string) $nonNegative);
28+
assertType("'-1'|'-10'|'-2'|'-3'|'-4'|'-5'|'-6'|'-7'|'-8'|'-9'|'0'|'1'|'10'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'", (string) $withZero);
29+
assertType("''|'1'", (string) $bool);
30+
assertType("'1'", (string) true);
31+
assertType("''", (string) false);
32+
assertType("'5'", (string) 5);
33+
assertType("'-5'", (string) -5);
34+
assertType('decimal-int-string', $int . '');
35+
assertType('decimal-int-string', strval($int));
36+
}
37+
}

‎tests/PHPStan/Analyser/nsrt/bug-4587.php‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ public function b(): void
2727
$type = array_map(static function (array $result): array {
2828
assertType('array{a: int}', $result);
2929
$result['a'] = (string) $result['a'];
30-
assertType('array{a: lowercase-string&numeric-string&uppercase-string}', $result);
30+
assertType('array{a: decimal-int-string}', $result);
3131

3232
return $result;
3333
}, $results);
3434

35-
assertType('list<array{a: lowercase-string&numeric-string&uppercase-string}>', $type);
35+
assertType('list<array{a: decimal-int-string}>', $type);
3636
}
3737
}

‎tests/PHPStan/Analyser/nsrt/bug-7387.php‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public function inputTypes(int $i, float $f, string $s, int $intRange) {
2929

3030
public function specifiers(int $i) {
3131
// https://3v4l.org/fmVIg
32-
assertType('lowercase-string&numeric-string&uppercase-string', sprintf('%14s', $i));
32+
assertType('decimal-int-string', sprintf('%14s', $i));
3333

3434
assertType('lowercase-string&numeric-string', sprintf('%d', $i));
3535

@@ -59,9 +59,9 @@ public function specifiers(int $i) {
5959
*/
6060
public function positionalArgs($mixed, int $i, float $f, string $s, int $posInt, int $negInt, int $nonZeroIntRange, int $intRange) {
6161
// https://3v4l.org/vVL0c
62-
assertType('lowercase-string&numeric-string&uppercase-string', sprintf('%2$6s', $mixed, $i));
63-
assertType('lowercase-string&non-falsy-string&numeric-string&uppercase-string', sprintf('%2$6s', $mixed, $posInt));
64-
assertType('lowercase-string&non-falsy-string&numeric-string&uppercase-string', sprintf('%2$6s', $mixed, $negInt));
62+
assertType('decimal-int-string', sprintf('%2$6s', $mixed, $i));
63+
assertType('decimal-int-string&non-falsy-string', sprintf('%2$6s', $mixed, $posInt));
64+
assertType('decimal-int-string&non-falsy-string', sprintf('%2$6s', $mixed, $negInt));
6565
assertType("' 1'|' 2'|' 3'|' 4'|' 5'", sprintf('%2$6s', $mixed, $nonZeroIntRange));
6666

6767
// https://3v4l.org/1ECIq

‎tests/PHPStan/Analyser/nsrt/bug-8635.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ class HelloWorld
88
{
99
public function EchoInt(int $value): void
1010
{
11-
assertType('lowercase-string&numeric-string&uppercase-string', "$value");
11+
assertType('decimal-int-string', "$value");
1212
}
1313
}

0 commit comments

Comments
 (0)