Skip to content

Commit f8dd187

Browse files
phpstan-botclaudestaabm
authored
Re-check scalar types after integer range expansion in TypeCombinator::union (#5660)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Markus Staab <maggus.staab@googlemail.com>
1 parent fb53a12 commit f8dd187

4 files changed

Lines changed: 113 additions & 1 deletion

File tree

src/Type/TypeCombinator.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,8 +353,9 @@ public static function union(Type ...$types): Type
353353
[$a, $b] = $compareResult;
354354
if ($a !== null) {
355355
$types[$i] = $a;
356-
array_splice($scalarTypeItems, $j--, 1);
356+
array_splice($scalarTypeItems, $j, 1);
357357
$scalarTypeItemsCount--;
358+
$j = -1;
358359
continue 1;
359360
}
360361
if ($b !== null) {
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
namespace Bug14610;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
function test(): void
8+
{
9+
$value = 0;
10+
11+
if (isset($_SESSION['test'])) {
12+
$value = rand(0,3);
13+
if ($value == 1) {
14+
}
15+
}
16+
17+
assertType('int<0, 3>', $value);
18+
19+
if ($value == 0) {
20+
assertType('array<mixed>', $_SESSION);
21+
$result = isset($_SESSION['test']); // should not be reported as always exists
22+
}
23+
}
24+
25+
function testWithOtherSuperglobals(): void
26+
{
27+
$value = 0;
28+
29+
if (isset($_GET['key'])) {
30+
$value = rand(0,3);
31+
if ($value == 1) {
32+
}
33+
}
34+
35+
if ($value == 0) {
36+
$result = isset($_GET['key']);
37+
}
38+
}
39+
40+
function testWithStrictComparison(): void
41+
{
42+
$value = 0;
43+
44+
if (isset($_SESSION['test'])) {
45+
$value = rand(0,3);
46+
if ($value === 1) {
47+
}
48+
}
49+
50+
if ($value === 0) {
51+
$result = isset($_SESSION['test']);
52+
}
53+
}
54+
55+
function testWithDifferentKey(): void
56+
{
57+
$value = 0;
58+
59+
if (isset($_SESSION['test'])) {
60+
$value = rand(0,3);
61+
if ($value == 1) {
62+
}
63+
}
64+
65+
if ($value == 0) {
66+
$result = isset($_SESSION['other']);
67+
}
68+
}

tests/PHPStan/Rules/Variables/IssetRuleTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,4 +574,11 @@ public function testBug14393(): void
574574
]);
575575
}
576576

577+
public function testBug14610(): void
578+
{
579+
$this->treatPhpDocTypesAsCertain = true;
580+
581+
$this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-14610.php'], []);
582+
}
583+
577584
}

tests/PHPStan/Type/TypeCombinatorTest.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1642,6 +1642,42 @@ public static function dataUnion(): iterable
16421642
IntegerType::class,
16431643
'int',
16441644
],
1645+
[
1646+
[
1647+
new UnionType([
1648+
new ConstantIntegerType(0),
1649+
IntegerRangeType::fromInterval(2, 3),
1650+
]),
1651+
new ConstantIntegerType(1),
1652+
],
1653+
IntegerRangeType::class,
1654+
'int<0, 3>',
1655+
],
1656+
[
1657+
[
1658+
new ConstantIntegerType(1),
1659+
new UnionType([
1660+
new ConstantIntegerType(0),
1661+
IntegerRangeType::fromInterval(2, 3),
1662+
]),
1663+
],
1664+
IntegerRangeType::class,
1665+
'int<0, 3>',
1666+
],
1667+
[
1668+
[
1669+
new UnionType([
1670+
new ConstantIntegerType(0),
1671+
IntegerRangeType::fromInterval(2, 3),
1672+
]),
1673+
new UnionType([
1674+
new ConstantIntegerType(10),
1675+
new ConstantIntegerType(1),
1676+
]),
1677+
],
1678+
UnionType::class,
1679+
'10|int<0, 3>',
1680+
],
16451681
[
16461682
[
16471683
new MixedType(),

0 commit comments

Comments
 (0)