Skip to content

Commit 6d06e52

Browse files
phpstan-botclaude
andcommitted
Add unsealed-array variants of array_flip/array_fill_keys union-value tests
Mirror the sealed bug-14656 cases with unsealed array shapes (`...<int, V>` tails) to lock in the per-key value precision across the unsealed extras: a finite union tail decomposes into optional explicit slots merged with the explicit keys, while a non-finite tail (e.g. `string`) survives as unsealed extras with overlapping explicit values widened. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent f5f920e commit 6d06e52

1 file changed

Lines changed: 54 additions & 0 deletions

File tree

tests/PHPStan/Analyser/nsrt/bug-14656.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,57 @@ public function mixedUnionAndConstant(array $a): void
4545
assertType("array{a?: 'x', b?: 'x', c: 'x'}", array_fill_keys($a, 'x'));
4646
}
4747
}
48+
49+
class ArrayFlipUnsealedUnionValues
50+
{
51+
/** @param array{0: 'a'|'b'|'c', 1: 'a'|'b'|'c', 2: 'a'|'b'|'c', ...<int, 'a'|'b'|'c'>} $a */
52+
public function allUnion(array $a): void
53+
{
54+
assertType("non-empty-array{a?: int, b?: int, c?: int}", array_flip($a));
55+
}
56+
57+
/** @param array{0: 'a'|'b', 1: 'b'|'c', ...<int, 'a'|'b'|'c'>} $a */
58+
public function overlappingUnion(array $a): void
59+
{
60+
assertType("non-empty-array{a?: int, b?: int, c?: int}", array_flip($a));
61+
}
62+
63+
/** @param array{0: 'a'|'b', 1: 'c', ...<int, 'a'|'b'>} $a */
64+
public function mixedUnionAndConstant(array $a): void
65+
{
66+
assertType("array{a?: int, b?: int, c: 1}", array_flip($a));
67+
}
68+
69+
/** @param array{0: 'a'|'b', 1: 'c', ...<int, string>} $a */
70+
public function nonFiniteTail(array $a): void
71+
{
72+
assertType("array{a?: int, b?: int, c: int, ...<string, int>}", array_flip($a));
73+
}
74+
}
75+
76+
class ArrayFillKeysUnsealedUnionValues
77+
{
78+
/** @param array{0: 'a'|'b', 1: 'b'|'c', ...<int, 'a'|'b'|'c'>} $a */
79+
public function overlappingUnion(array $a): void
80+
{
81+
assertType("non-empty-array{a?: 'x', b?: 'x', c?: 'x'}", array_fill_keys($a, 'x'));
82+
}
83+
84+
/** @param array{0: 'a'|'b'|'c', 1: 'a'|'b'|'c', 2: 'a'|'b'|'c', ...<int, 'a'|'b'|'c'>} $a */
85+
public function allUnion(array $a): void
86+
{
87+
assertType("non-empty-array{a?: 'x', b?: 'x', c?: 'x'}", array_fill_keys($a, 'x'));
88+
}
89+
90+
/** @param array{0: 'a'|'b', 1: 'c', ...<int, 'a'|'b'>} $a */
91+
public function mixedUnionAndConstant(array $a): void
92+
{
93+
assertType("array{a?: 'x', b?: 'x', c: 'x'}", array_fill_keys($a, 'x'));
94+
}
95+
96+
/** @param array{0: 'a'|'b', 1: 'c', ...<int, string>} $a */
97+
public function nonFiniteTail(array $a): void
98+
{
99+
assertType("array{a?: 'x', b?: 'x', c: 'x', ...<string, 'x'>}", array_fill_keys($a, 'x'));
100+
}
101+
}

0 commit comments

Comments
 (0)