Skip to content

Commit 925eabb

Browse files
authored
Fix huge union types result from "+"-array-merge operation
1 parent 9571283 commit 925eabb

File tree

5 files changed

+175
-1
lines changed

5 files changed

+175
-1
lines changed

src/Analyser/MutatingScope.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1314,7 +1314,10 @@ private function resolveType(Expr $node): Type
13141314
$leftConstantArrays = TypeUtils::getConstantArrays($leftType);
13151315
$rightConstantArrays = TypeUtils::getConstantArrays($rightType);
13161316

1317-
if (count($leftConstantArrays) > 0 && count($rightConstantArrays) > 0) {
1317+
$leftCount = count($leftConstantArrays);
1318+
$rightCount = count($rightConstantArrays);
1319+
if ($leftCount > 0 && $rightCount > 0
1320+
&& ($leftCount + $rightCount < ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT)) {
13181321
$resultTypes = [];
13191322
foreach ($rightConstantArrays as $rightConstantArray) {
13201323
foreach ($leftConstantArrays as $leftConstantArray) {

tests/PHPStan/Analyser/AnalyserIntegrationTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,12 @@ public function testTwoSameClassesInSingleFile(): void
248248
$this->assertSame(36, $error->getLine());
249249
}
250250

251+
public function testBug6936(): void
252+
{
253+
$errors = $this->runAnalyse(__DIR__ . '/data/bug-6936.php');
254+
$this->assertNoErrors($errors);
255+
}
256+
251257
public function testBug3405(): void
252258
{
253259
$errors = $this->runAnalyse(__DIR__ . '/data/bug-3405.php');

tests/PHPStan/Analyser/NodeScopeResolverTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,7 @@ public function dataFileAsserts(): iterable
838838
yield from $this->gatherAssertTypes(__DIR__ . '/data/array-fill-keys.php');
839839

840840
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-6917.php');
841+
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-6936-limit.php');
841842
}
842843

843844
/**
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
namespace Bug6936Limits;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class Foo
8+
{
9+
/**
10+
* @return void
11+
*/
12+
public function testLimits():void
13+
{
14+
$arr2 = [1,2,3];
15+
16+
$arr = [];
17+
if (rand(0,1)) {
18+
$arr[] = 'a';
19+
}
20+
if (rand(0,1)) {
21+
$arr[] = 'b';
22+
}
23+
if (rand(0,1)) {
24+
$arr[] = 'c';
25+
}
26+
if (rand(0,1)) {
27+
$arr[] = 'd';
28+
}
29+
if (rand(0,1)) {
30+
$arr[] = 'e';
31+
}
32+
if (rand(0,1)) {
33+
$arr[] = 'f';
34+
}
35+
if (rand(0,1)) {
36+
$arr[] = 'g';
37+
}
38+
39+
assertType("array{0: 1|'a'|'b'|'c'|'d'|'e'|'f'|'g', 1: 2|'b', 2: 3|'c', 3?: 'd', 4?: 'e', 5?: 'f', 6?: 'g'}", $arr + $arr2);
40+
if (rand(0,1)) {
41+
$arr[] = 'h';
42+
}
43+
44+
assertType("array{0: 1|'a'|'b'|'c'|'d'|'e'|'f'|'g'|'h', 1: 2|'b', 2: 3|'c', 3?: 'd', 4?: 'e', 5?: 'f', 6?: 'g', 7?: 'h'}", $arr + $arr2);
45+
if (rand(0,1)) {
46+
$arr[] = 'i';
47+
}
48+
49+
// fallback to a less precise form, which reduces the union-type size
50+
assertType("non-empty-array<0|1|2|3|4|5|6|7|8, 1|2|3|'a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'i'>", $arr + $arr2);
51+
}
52+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<?php
2+
3+
namespace Bug6936;
4+
5+
class clxAuftragController
6+
{
7+
public function save_auftrag_changes():void
8+
{
9+
foreach ($_POST['adansch'] as $avkid => $adansch) {
10+
$aktueller_endkunde = new x();
11+
$avk = new avk();
12+
$change = 0;
13+
$col = [];
14+
if ($adansch['telefon'] != $aktueller_endkunde->telefon && '' != $adansch['telefon']) {
15+
$col['telefon'] = $adansch['telefon'];
16+
$change = 1;
17+
}
18+
if ($adansch['email'] != $aktueller_endkunde->email && '' != $adansch['email']) {
19+
$col['email'] = $adansch['email'];
20+
$change = 1;
21+
}
22+
if ($adansch['fa_gruendungsjahr'] != $aktueller_endkunde->fa_gruendungsjahr) {
23+
$col['fa_gruendungsjahr'] = $adansch['fa_gruendungsjahr'];
24+
$change = 1;
25+
}
26+
if ($adansch['fa_geschaeftsfuehrer'] != $aktueller_endkunde->fa_geschaeftsfuehrer) {
27+
$col['fa_geschaeftsfuehrer'] = $adansch['fa_geschaeftsfuehrer'];
28+
$change = 1;
29+
}
30+
if ($adansch['handelregnr'] != $aktueller_endkunde->handelregnr) {
31+
$col['handelregnr'] = $adansch['handelregnr'];
32+
$change = 1;
33+
}
34+
if ($adansch['amtsgericht'] != $aktueller_endkunde->amtsgericht) {
35+
$col['amtsgericht'] = $adansch['amtsgericht'];
36+
$change = 1;
37+
}
38+
if ($adansch['ustid'] != $aktueller_endkunde->ustid) {
39+
$col['ustid'] = $adansch['ustid'];
40+
$change = 1;
41+
}
42+
if ($adansch['ustnr'] != $aktueller_endkunde->ustnr) {
43+
$col['ustnr'] = $adansch['ustnr'];
44+
$change = 1;
45+
}
46+
47+
if ($adansch['firma'] != $aktueller_endkunde->firma) {
48+
$col['firma'] = $adansch['firma'];
49+
$change = 1;
50+
}
51+
52+
if (1 == $change) {
53+
// MobisHelper::createXmlDataJob("ada",(int)$aktueller_endkunde->adaid, $col);
54+
if (!isset($_SENDJOB[$avk->avkid]['ada'][$aktueller_endkunde->adaid])) {
55+
$_SENDJOB[$avk->avkid]['ada'][$aktueller_endkunde->adaid] = [];
56+
}
57+
58+
$_SENDJOB[$avk->avkid]['ada'][$aktueller_endkunde->adaid] = $_SENDJOB[$avk->avkid]['ada'][$aktueller_endkunde->adaid] + $col;
59+
}
60+
}
61+
}
62+
}
63+
64+
65+
class x {
66+
/**
67+
* @var int
68+
*/
69+
public $adaid;
70+
/**
71+
* @var string
72+
*/
73+
public $telefon;
74+
/**
75+
* @var string
76+
*/
77+
public $email;
78+
/**
79+
* @var string
80+
*/
81+
public $fa_gruendungsjahr;
82+
/**
83+
* @var string
84+
*/
85+
public $fa_geschaeftsfuehrer;
86+
/**
87+
* @var string
88+
*/
89+
public $handelregnr;
90+
/**
91+
* @var string
92+
*/
93+
public $amtsgericht;
94+
/**
95+
* @var string
96+
*/
97+
public $ustid;
98+
/**
99+
* @var string
100+
*/
101+
public $ustnr;
102+
/**
103+
* @var string
104+
*/
105+
public $firma;
106+
}
107+
class avk {
108+
/**
109+
* @var int
110+
*/
111+
public $avkid;
112+
}

0 commit comments

Comments
 (0)