forked from phpstan/phpstan-src
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbug-14336.php
More file actions
156 lines (140 loc) · 4.22 KB
/
bug-14336.php
File metadata and controls
156 lines (140 loc) · 4.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
<?php
namespace Bug14336;
use function PHPStan\Testing\assertType;
/**
* Actual reproducer from the issue: nested dim fetch with arbitrary int key
* after resetting array element to [].
*
* @param array<string, list<array{xmlNamespace: string, namespace: string, name: string}>> $xsdFiles
* @param array<string, list<array{xmlNamespace: string, namespace: string, name: string}>> $groupedByNamespace
* @param array<string, list<string>> $extraNamespaces
*/
function testIssueReproducer(array $xsdFiles, array $groupedByNamespace, array $extraNamespaces, int $int): void
{
foreach ($extraNamespaces as $mergedNamespace) {
if (count($mergedNamespace) < 2) {
continue;
}
$targetNamespace = end($mergedNamespace);
if (!isset($groupedByNamespace[$targetNamespace])) {
continue;
}
$xmlNamespace = $groupedByNamespace[$targetNamespace][0]['xmlNamespace'];
assertType('string', $xmlNamespace);
assertType('non-empty-list<string>&hasOffsetValue(1, string)', $mergedNamespace);
$xsdFiles[$xmlNamespace] = [];
foreach ($mergedNamespace as $namespace) {
foreach ($groupedByNamespace[$namespace] ?? [] as $viewHelper) {
$xsdFiles[$xmlNamespace][$int] = $viewHelper;
}
}
// After assigning any int, $xsdFiles[$xmlNamespace] should NOT be a list
assertType('array<int, array{xmlNamespace: string, namespace: string, name: string}>', $xsdFiles[$xmlNamespace]);
$xsdFiles[$xmlNamespace] = array_values($xsdFiles[$xmlNamespace]);
}
}
/**
* Simplified: nested dim fetch after reset with arbitrary int key.
*
* @param array<string, list<array{name: string}>> $arr
*/
function testNestedDimFetchAfterReset(array $arr, int $int, string $key): void
{
$arr[$key] = [];
$arr[$key][$int] = ['name' => 'test'];
assertType("non-empty-array<int, array{name: string}>", $arr[$key]);
}
/**
* Assigning with arbitrary int key in a loop should degrade list to array.
*
* @param list<array{abc: string}> $list
* @param array<int, int> $intMap
*/
function testAssignAnyIntInLoop(array $list, array $intMap): void
{
foreach ($intMap as $intKey => $intValue) {
$list[$intKey] = ['abc' => 'def'];
}
assertType("array<int, array{abc: string}>", $list);
}
/**
* @param list<string> $list
* @param int $intKey
*/
function testAssignAnyIntOutsideLoop(array $list, int $intKey): void
{
$list[$intKey] = 'foo';
assertType("non-empty-array<int, string>", $list);
}
/**
* Safe patterns should still preserve list.
*
* @param list<string> $list
*/
function testKeepListWithAppend(array $list): void
{
$list[] = 'foo';
assertType("non-empty-list<string>", $list);
}
/**
* @param list<string> $list
*/
function testKeepListWithConstantZero(array $list): void
{
$list[0] = 'foo';
assertType("non-empty-list<string>&hasOffsetValue(0, 'foo')", $list);
}
/**
* Nested array assignment in loop should keep outer list when key comes from iteration.
*
* @param list<array<string, string>> $list
*/
function testNestedAssignKeepsList(array $list): void
{
foreach ($list as $k => $v) {
$list[$k]['abc'] = 'world';
}
assertType("list<non-empty-array<string, string>&hasOffsetValue('abc', 'world')>", $list);
}
/**
* @param list<list<string>> $list
* @param int $intKey
*/
function testNestedListAssignWithAnyInt(array $list, int $intKey): void
{
$list[$intKey] = ['foo'];
assertType("non-empty-array<int, list<string>>", $list);
}
/**
* Assigning with negative int key should also degrade list.
*
* @param list<string> $list
* @param int<min, -1> $negativeKey
*/
function testAssignNegativeInt(array $list, int $negativeKey): void
{
$list[$negativeKey] = 'foo';
assertType("non-empty-array<int, string>", $list);
}
/**
* Assigning with int<0, max> should still keep list (valid range).
*
* @param list<array<string>> $list
* @param int<0, max> $nonNegativeKey
*/
function testAssignNonNegativeIntWithArrayValue(array $list, int $nonNegativeKey): void
{
$list[$nonNegativeKey] = ['foo'];
assertType("non-empty-list<array<string>>", $list);
}
/**
* Direct scalar assignment with int<0, max> key.
*
* @param list<string> $list
* @param int<0, max> $nonNegativeKey
*/
function testAssignNonNegativeIntWithScalarValue(array $list, int $nonNegativeKey): void
{
$list[$nonNegativeKey] = 'foo';
assertType("non-empty-array<int<0, max>, string>", $list);
}