Skip to content

Commit b4430ff

Browse files
committed
Merge branch 2.1.x into 2.2.x
2 parents 55db2be + f0f92bc commit b4430ff

3 files changed

Lines changed: 186 additions & 2 deletions

File tree

src/Type/IntersectionType.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1203,7 +1203,13 @@ public function shiftArray(): Type
12031203

12041204
public function shuffleArray(): Type
12051205
{
1206-
return $this->intersectTypes(static fn (Type $type): Type => $type->shuffleArray());
1206+
$isList = $this->isList()->yes();
1207+
return $this->intersectTypes(static function (Type $type) use ($isList): Type {
1208+
if ($isList && $type instanceof TemplateType) {
1209+
return $type;
1210+
}
1211+
return $type->shuffleArray();
1212+
});
12071213
}
12081214

12091215
public function sliceArray(Type $offsetType, Type $lengthType, TrinaryLogic $preserveKeys): Type
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Bug14631;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class Foo
8+
{
9+
10+
/**
11+
* @template T
12+
* @param T&list<int> $items
13+
* @return T&list<int>
14+
*/
15+
public function sortList(array $items): array
16+
{
17+
assertType('list<int>&T (method Bug14631\Foo::sortList(), argument)', $items);
18+
usort($items, function (int $a, int $b) {
19+
return $a <=> $b;
20+
});
21+
22+
assertType('list<int>&T (method Bug14631\Foo::sortList(), argument)', $items);
23+
24+
return $items;
25+
}
26+
27+
/**
28+
* @template T
29+
* @param T&array<string, int> $items
30+
* @return T&array<string, int>
31+
*/
32+
public function sortArray(array $items): array
33+
{
34+
assertType('array<string, int>&T (method Bug14631\Foo::sortArray(), argument)', $items);
35+
usort($items, function (int $a, int $b) {
36+
return $a <=> $b;
37+
});
38+
39+
// T should be dropped because keys changed from string to int
40+
assertType('list<int>', $items);
41+
42+
return $items;
43+
}
44+
45+
/**
46+
* @template T
47+
* @param T&list<int> $items
48+
* @return T&list<int>
49+
*/
50+
public function sortListSort(array $items): array
51+
{
52+
sort($items);
53+
assertType('list<int>&T (method Bug14631\Foo::sortListSort(), argument)', $items);
54+
return $items;
55+
}
56+
57+
/**
58+
* @template T
59+
* @param T&list<int> $items
60+
* @return T&list<int>
61+
*/
62+
public function sortListRsort(array $items): array
63+
{
64+
rsort($items);
65+
assertType('list<int>&T (method Bug14631\Foo::sortListRsort(), argument)', $items);
66+
return $items;
67+
}
68+
69+
/**
70+
* @template T
71+
* @param T&list<int> $items
72+
* @return T&list<int>
73+
*/
74+
public function sortListShuffle(array $items): array
75+
{
76+
shuffle($items);
77+
assertType('list<int>&T (method Bug14631\Foo::sortListShuffle(), argument)', $items);
78+
return $items;
79+
}
80+
81+
/**
82+
* @template T
83+
* @param T&array<string, int> $items
84+
* @return T&array<string, int>
85+
*/
86+
public function sortArraySort(array $items): array
87+
{
88+
sort($items);
89+
// T dropped: keys changed from string to int
90+
assertType('list<int>', $items);
91+
return $items;
92+
}
93+
94+
/**
95+
* @template T
96+
* @param T&array<string, int> $items
97+
* @return T&array<string, int>
98+
*/
99+
public function sortArrayRsort(array $items): array
100+
{
101+
rsort($items);
102+
// T dropped: keys changed from string to int
103+
assertType('list<int>', $items);
104+
return $items;
105+
}
106+
107+
/**
108+
* @template T
109+
* @param T&array<string, int> $items
110+
* @return T&array<string, int>
111+
*/
112+
public function shuffleArray(array $items): array
113+
{
114+
shuffle($items);
115+
// T dropped: keys changed from string to int
116+
assertType('list<int>', $items);
117+
return $items;
118+
}
119+
120+
/**
121+
* @template T
122+
* @param T&list<int> $items
123+
* @return T&list<int>
124+
*/
125+
public function uasortList(array $items): array
126+
{
127+
uasort($items, function (int $a, int $b) {
128+
return $a <=> $b;
129+
});
130+
131+
// T preserved, list-ness dropped (key-preserving sort may reorder)
132+
assertType('array<int<0, max>, int>&T (method Bug14631\Foo::uasortList(), argument)', $items);
133+
return $items;
134+
}
135+
136+
/**
137+
* @template T
138+
* @param T&array<string, int> $items
139+
* @return T&array<string, int>
140+
*/
141+
public function uasortArray(array $items): array
142+
{
143+
uasort($items, function (int $a, int $b) {
144+
return $a <=> $b;
145+
});
146+
147+
// T preserved: key-preserving sort doesn't change keys
148+
assertType('array<string, int>&T (method Bug14631\Foo::uasortArray(), argument)', $items);
149+
return $items;
150+
}
151+
152+
/**
153+
* @template T
154+
* @param T&array<string, int> $items
155+
* @return T&array<string, int>
156+
*/
157+
public function asortArray(array $items): array
158+
{
159+
asort($items);
160+
// T preserved: key-preserving sort
161+
assertType('array<string, int>&T (method Bug14631\Foo::asortArray(), argument)', $items);
162+
return $items;
163+
}
164+
165+
/**
166+
* @template T
167+
* @param T&array<string, int> $items
168+
* @return T&array<string, int>
169+
*/
170+
public function ksortArray(array $items): array
171+
{
172+
ksort($items);
173+
// T preserved: key-preserving sort
174+
assertType('array<string, int>&T (method Bug14631\Foo::ksortArray(), argument)', $items);
175+
return $items;
176+
}
177+
178+
}

tests/PHPStan/Analyser/nsrt/sort.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ public function doFoo(array $array)
145145
return $a['a'] <=> $b['a'];
146146
});
147147

148-
assertType('list<array{a: bool|float|int|string, b: true}>', $array);
148+
assertType('list<array{a: bool|float|int|string, b: true}>&T (method Sort\Bar::doFoo(), argument)', $array);
149149

150150
return $array;
151151
}

0 commit comments

Comments
 (0)