Skip to content

Commit ca03191

Browse files
committed
Collapse array members of one shape with different accessories to the shape
Keeping the first of two members whose stripped shapes describe the same dropped the values of the other one: the union of non-empty-array&hasOffset('foo') and array became non-empty-array&hasOffset('foo'). Such members now collapse to their stripped shape, and the accessories they share are intersected back. Amp-Thread-ID: https://ampcode.com/threads/T-01a19219-6260-7460-a52b-a418f709e4bf
1 parent 51ff531 commit ca03191

23 files changed

Lines changed: 76 additions & 53 deletions

‎src/Type/TypeCombinator.php‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,10 +1297,22 @@ private static function processArrayTypes(array $arrayTypes): array
12971297
// per-element accessories like hasOffsetValue (cf. the optional-
12981298
// properties repro: 4 same-shape members differing only in stacked
12991299
// hasOffsetValue accessories), while preserving per-member accessories
1300-
// like list / non-empty on whichever original survives.
1300+
// like list / non-empty when only one original has the shape. Two
1301+
// originals of one shape that differ in their accessories collapse to
1302+
// the stripped shape: keeping either of them would drop values of the
1303+
// other, and the accessories they share are added back below.
13011304
$deduped = [];
13021305
foreach ($strippedArrays as $i => $stripped) {
1303-
$deduped[$stripped->describe(VerbosityLevel::cache())] ??= $arrayTypes[$i];
1306+
$key = $stripped->describe(VerbosityLevel::cache());
1307+
if (!array_key_exists($key, $deduped)) {
1308+
$deduped[$key] = $arrayTypes[$i];
1309+
continue;
1310+
}
1311+
if ($deduped[$key]->equals($arrayTypes[$i])) {
1312+
continue;
1313+
}
1314+
1315+
$deduped[$key] = $stripped;
13041316
}
13051317
$deduped = array_values($deduped);
13061318

‎tests/PHPStan/Analyser/nsrt/binary.php‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -369,12 +369,12 @@ public function doFoo(array $generalArray)
369369
assertType('0', min(0, ...[1, 2, 3]));
370370
assertType('array{5, 6, 9}', max([1, 10, 8], [5, 6, 9]));
371371
assertType('array{1, 1, 1, 1}', max(array(2, 2, 2), array(1, 1, 1, 1)));
372-
assertType('non-empty-array<int>&hasOffsetValue(108, int)&hasOffsetValue(42, int)', max($arrayOfUnknownIntegers, $arrayOfUnknownIntegers));
372+
assertType('array<int>', max($arrayOfUnknownIntegers, $arrayOfUnknownIntegers));
373373
assertType('array{1, 1, 1, 1}', max(array(2, 2, 2), 5, array(1, 1, 1, 1)));
374374
assertType('array{int, int, int}', max($arrayOfIntegers, 5));
375-
assertType('non-empty-array<int>&hasOffsetValue(108, int)&hasOffsetValue(42, int)', max($arrayOfUnknownIntegers, 5));
376-
assertType('(non-empty-array<int>&hasOffsetValue(108, int)&hasOffsetValue(42, int))|int', max($arrayOfUnknownIntegers, $integer, $arrayOfUnknownIntegers));
377-
assertType('non-empty-array<int>&hasOffsetValue(108, int)&hasOffsetValue(42, int)', max($arrayOfUnknownIntegers, $conditionalInt));
375+
assertType('array<int>', max($arrayOfUnknownIntegers, 5));
376+
assertType('array<int>|int', max($arrayOfUnknownIntegers, $integer, $arrayOfUnknownIntegers));
377+
assertType('array<int>', max($arrayOfUnknownIntegers, $conditionalInt));
378378
assertType('5', min($arrayOfIntegers, 5));
379379
assertType('5', min($arrayOfUnknownIntegers, 5));
380380
assertType('1|2', min($arrayOfUnknownIntegers, $conditionalInt));

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public function extract(SimpleXMLElement $data, string $type = 'Meta'): array
2525
$meta[$key] = [];
2626
assertType('array{}', $meta[$key]);
2727
foreach ($tag->{$valueName} as $value) {
28-
assertType('array{}|array{0: string, 1?: string}', $meta[$key]);
28+
assertType('list<string>|string', $meta[$key]);
2929
$meta[$key][] = (string)$value;
3030
}
3131
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ function testShouldLooseListbyAst(array $list, int $i): void
9494
$list[1+$i] = 21;
9595
assertType('non-empty-array<int<0, max>, int>', $list);
9696
}
97-
assertType('list<int>', $list);
97+
assertType('array<int<0, max>, int>', $list);
9898
}
9999

100100
/** @param list<int> $list */
@@ -105,5 +105,5 @@ function testShouldLooseListbyAst2(array $list, int $i): void
105105
$list[2+$i] = 21;
106106
assertType('non-empty-array<int<0, max>, int>', $list);
107107
}
108-
assertType('list<int>', $list);
108+
assertType('array<int<0, max>, int>', $list);
109109
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ function fooArr(array $arr): void {
1414
for ($i = 0; $i < count($arr); ++$i) {
1515
assertType('non-empty-array', $arr);
1616
}
17-
assertType('non-empty-array', $arr);
17+
assertType('array', $arr);
1818
}
1919

2020
/** @param list<mixed> $arr */
@@ -28,7 +28,7 @@ function foo(array $arr): void {
2828
for ($i = 0; $i < count($arr); ++$i) {
2929
assertType('non-empty-list<mixed>', $arr);
3030
}
31-
assertType('non-empty-list<mixed>', $arr);
31+
assertType('list<mixed>', $arr);
3232
}
3333

3434

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,16 @@ function countLessThanRange(array $arr, int $boundedRange, int $unboundedMaxRang
3636

3737
// count($arr) < unbounded max range → falsey + max is null → fallback via min (branch 3/4)
3838
if (count($arr) < $unboundedMaxRange) {
39-
assertType('non-empty-list<string>&hasOffsetValue(1, string)', $arr);
39+
assertType('list<string>', $arr);
4040
} else {
4141
assertType('non-empty-list<string>&hasOffsetValue(1, string)', $arr);
4242
}
4343

4444
// count($arr) < unbounded min range → fallback branch (min is null)
4545
if (count($arr) < $unboundedMinRange) {
46-
assertType('non-empty-list<string>&hasOffsetValue(1, string)', $arr);
46+
assertType('list<string>', $arr);
4747
} else {
48-
assertType('non-empty-list<string>&hasOffsetValue(1, string)', $arr);
48+
assertType('list<string>', $arr);
4949
}
5050
}
5151

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,5 @@ function example3(array &$convert): void
4242
$convert[$outerKey][$key] = strtoupper($val);
4343
}
4444
}
45-
assertType('array<string, non-empty-list<string>>', $convert);
45+
assertType('array<string, list<string>>', $convert);
4646
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ public function doBar(array $list): void
2828
if (count($list) > 1) {
2929
assertType('int<2, max>', count($list));
3030
foreach ($list as $key => $item) {
31-
assertType('int<2, max>', count($list));
31+
assertType('0|int<2, max>', count($list));
3232
if ($item === false) {
3333
unset($list[$key]);
3434
assertType('int<0, max>', count($list));
3535
}
3636

37-
assertType('int<1, max>', count($list));
37+
assertType('int<0, max>', count($list));
3838

3939
if (count($list) === 1) {
4040
assertType('1', count($list));
@@ -44,7 +44,7 @@ public function doBar(array $list): void
4444
}
4545
}
4646

47-
assertType('int<1, max>', count($list));
47+
assertType('int<0, max>', count($list));
4848
}
4949

5050
assertType('int<0, max>', count($list));

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ function GetASCConfig()
8787
}
8888
}
8989

90-
assertType("non-empty-array<int|string>&hasOffsetValue('bew', int)&hasOffsetValue('bsw', int)", $result);
90+
assertType("non-empty-array<mixed~('ssi'|'utc'), int|string>&hasOffsetValue('bew', int)&hasOffsetValue('bsw', int)", $result);
9191
}
9292

9393
assertType("(non-empty-array<int|string>&hasOffsetValue('bew', int)&hasOffsetValue('bsw', int))|array{result: false, dberror: 'xyz'}", $result);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@ function test() {
2222
}
2323
}
2424

25-
assertType('true',sizeof($items) > 0);
25+
assertType('bool',sizeof($items) > 0);
2626
}

0 commit comments

Comments
 (0)