Skip to content

Commit 914b0de

Browse files
committed
Infer mixed array shape merges
Use the generic key and value approximation when constant shapes are merged with generic arrays. Preserve the guaranteed array fallback for unioned constant shapes, with coverage for named, optional, numeric, and union cases.
1 parent 52ed600 commit 914b0de

3 files changed

Lines changed: 23 additions & 2 deletions

File tree

src/ArrayMergeType.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ protected function getResult(): Type
200200
return $builder->getArray();
201201
}
202202

203-
if ($nConstantLists + $nOtherArrays === count($this->types)) {
203+
if ($nConstantArrays + $nOtherArrays === count($this->types)) {
204204
$allIntegerKeys = true;
205205
$atLeastOneNonEmpty = false;
206206
$combinedKeyType = null;
@@ -209,7 +209,7 @@ protected function getResult(): Type
209209
foreach ($this->types as $type) {
210210
/** @TODO don't handle more than one atm */
211211
if (count($type->getArrays()) !== 1) {
212-
return new MixedType();
212+
return new ArrayType(new MixedType(true), new MixedType(true));
213213
}
214214

215215
if ($type->isIterableAtLeastOnce()->yes()) {

tests/ArrayMergeTypeNodeResolverExtensionTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public static function dataFileProvider(): \Generator
4242
yield [__DIR__ . '/data/generic.php'];
4343
yield [__DIR__ . '/data/generic-constant-list.php'];
4444
yield [__DIR__ . '/data/generic-const.php'];
45+
yield [__DIR__ . '/data/mixed-shapes.php'];
4546
yield [__DIR__ . '/data/mixed-lists.php'];
4647
yield [__DIR__ . '/data/multi-const-var.php'];
4748
yield [__DIR__ . '/data/nested.php'];

tests/data/mixed-shapes.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace jbboehr\PHPStan\ArrayMerge\Tests\Data;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
/** @phpstan-var array-merge<array{fixed: int}, array<string, string>> $constantFirst */
8+
assertType('non-empty-array<string, int|string>', $constantFirst);
9+
10+
/** @phpstan-var array-merge<array<string, string>, array{fixed: int}> $constantLast */
11+
assertType('non-empty-array<string, int|string>', $constantLast);
12+
13+
/** @phpstan-var array-merge<array{fixed?: int}, array<string, string>> $possiblyEmpty */
14+
assertType('array<string, int|string>', $possiblyEmpty);
15+
16+
/** @phpstan-var array-merge<array{2: int}, array<int, string>> $numericKeys */
17+
assertType('non-empty-list<int|string>', $numericKeys);
18+
19+
/** @phpstan-var array-merge<array{a: int}|array{b: string}, array<string, bool>> $unionedShapes */
20+
assertType('array<mixed, mixed>', $unionedShapes);

0 commit comments

Comments
 (0)