Skip to content

Commit 2e65472

Browse files
herndlmondrejmirtes
authored andcommitted
Fix return type of array_reverse() with optional keys
1 parent c4ba434 commit 2e65472

File tree

4 files changed

+33
-8
lines changed

4 files changed

+33
-8
lines changed

src/Type/Constant/ConstantArrayType.php

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@
5151
use function array_merge;
5252
use function array_pop;
5353
use function array_push;
54-
use function array_reverse;
5554
use function array_slice;
5655
use function array_unique;
5756
use function array_values;
@@ -892,14 +891,16 @@ public function popArray(): Type
892891

893892
public function reverseArray(TrinaryLogic $preserveKeys): Type
894893
{
895-
$keyTypesReversed = array_reverse($this->keyTypes, true);
896-
$keyTypes = array_values($keyTypesReversed);
897-
$keyTypesReversedKeys = array_keys($keyTypesReversed);
898-
$optionalKeys = array_map(static fn (int $optionalKey): int => $keyTypesReversedKeys[$optionalKey], $this->optionalKeys);
894+
$builder = ConstantArrayTypeBuilder::createEmpty();
899895

900-
$reversed = new self($keyTypes, array_reverse($this->valueTypes), $this->nextAutoIndexes, $optionalKeys, TrinaryLogic::createNo());
896+
for ($i = count($this->keyTypes) - 1; $i >= 0; $i--) {
897+
$offsetType = $preserveKeys->yes() || $this->keyTypes[$i]->isInteger()->no()
898+
? $this->keyTypes[$i]
899+
: null;
900+
$builder->setOffsetValueType($offsetType, $this->valueTypes[$i], $this->isOptionalKey($i));
901+
}
901902

902-
return $preserveKeys->yes() ? $reversed : $reversed->reindex();
903+
return $builder->getArray();
903904
}
904905

905906
public function searchArray(Type $needleType): Type

tests/PHPStan/Analyser/nsrt/array-reverse.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ public function normalArrays(array $a, array $b): void
2222
/**
2323
* @param array{a: 'foo', b: 'bar', c?: 'baz'} $a
2424
* @param array{17: 'foo', 19: 'bar'}|array{foo: 17, bar: 19} $b
25+
* @param array{0: 'A', 1?: 'B', 2?: 'C'} $c
2526
*/
26-
public function constantArrays(array $a, array $b): void
27+
public function constantArrays(array $a, array $b, array $c): void
2728
{
2829
assertType('array{}', array_reverse([]));
2930
assertType('array{}', array_reverse([], true));
@@ -45,6 +46,9 @@ public function constantArrays(array $a, array $b): void
4546

4647
assertType('array{\'bar\', \'foo\'}|array{bar: 19, foo: 17}', array_reverse($b));
4748
assertType('array{19: \'bar\', 17: \'foo\'}|array{bar: 19, foo: 17}', array_reverse($b, true));
49+
50+
assertType("array{0: 'A'|'B'|'C', 1?: 'A'|'B', 2?: 'A'}", array_reverse($c));
51+
assertType("array{2?: 'C', 1?: 'B', 0: 'A'}", array_reverse($c, true));
4852
}
4953

5054
/**

tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,4 +297,11 @@ public function testBug8881(): void
297297
$this->analyse([__DIR__ . '/data/bug-8881.php'], []);
298298
}
299299

300+
public function testBug11549(): void
301+
{
302+
$this->checkExplicitMixed = true;
303+
$this->checkNullables = true;
304+
$this->analyse([__DIR__ . '/data/bug-11549.php'], []);
305+
}
306+
300307
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
declare(strict_types = 1);
3+
4+
namespace Bug11549;
5+
6+
/**
7+
* @param array{0: string, 1?: string} $a
8+
* @return array{0: string, 1?: string}
9+
*/
10+
function rrr(array $a): array
11+
{
12+
return array_reverse($a);
13+
}

0 commit comments

Comments
 (0)