Skip to content

Commit

Permalink
Constant arrays should be preserved after sorting, just not as certai…
Browse files Browse the repository at this point in the history
…n lists
  • Loading branch information
ondrejmirtes committed Feb 23, 2024
1 parent ad34452 commit 0977a7b
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 11 deletions.
16 changes: 16 additions & 0 deletions src/Analyser/NodeScopeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -3207,6 +3207,22 @@ private function getArraySortDoNotPreserveListFunctionType(Type $type): Type
return $traverse($type);
}

$constantArrays = $type->getConstantArrays();
if (count($constantArrays) > 0) {
$types = [];
foreach ($constantArrays as $constantArray) {
$types[] = new ConstantArrayType(
$constantArray->getKeyTypes(),
$constantArray->getValueTypes(),
$constantArray->getNextAutoIndexes(),
$constantArray->getOptionalKeys(),
TrinaryLogic::createMaybe(),
);
}

return TypeCombinator::union(...$types);
}

$newArrayType = new ArrayType($type->getIterableKeyType(), $type->getIterableValueType());
if ($isIterableAtLeastOnce->yes()) {
$newArrayType = TypeCombinator::intersect($newArrayType, new NonEmptyArrayType());
Expand Down
5 changes: 4 additions & 1 deletion tests/PHPStan/Analyser/NodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,10 @@ public function dataFileAsserts(): iterable
}

yield from $this->gatherAssertTypes(__DIR__ . '/data/never.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-10627.php');

if (PHP_VERSION_ID >= 80100) {
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-10627.php');
}

yield from $this->gatherAssertTypes(__DIR__ . '/data/native-intersection.php');

Expand Down
33 changes: 25 additions & 8 deletions tests/PHPStan/Analyser/data/bug-10627.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Bug10627;

use function array_is_list;
use function PHPStan\Testing\assertType;

class HelloWorld
Expand All @@ -10,35 +11,40 @@ public function sayHello(): void
{
$list = ['A', 'C', 'B'];
natcasesort($list);
assertType("non-empty-array<0|1|2, 'A'|'B'|'C'>", $list);
assertType("array{'A', 'C', 'B'}", $list);
assertType('bool', array_is_list($list));
}

public function sayHello2(): void
{
$list = ['A', 'C', 'B'];
natsort($list);
assertType("non-empty-array<0|1|2, 'A'|'B'|'C'>", $list);
assertType("array{'A', 'C', 'B'}", $list);
assertType('bool', array_is_list($list));
}

public function sayHello3(): void
{
$list = ['A', 'C', 'B'];
arsort($list);
assertType("non-empty-array<0|1|2, 'A'|'B'|'C'>", $list);
assertType("array{'A', 'C', 'B'}", $list);
assertType('bool', array_is_list($list));
}

public function sayHello4(): void
{
$list = ['A', 'C', 'B'];
asort($list);
assertType("non-empty-array<0|1|2, 'A'|'B'|'C'>", $list);
assertType("array{'A', 'C', 'B'}", $list);
assertType('bool', array_is_list($list));
}

public function sayHello5(): void
{
$list = ['A', 'C', 'B'];
ksort($list);
assertType("non-empty-array<0|1|2, 'A'|'B'|'C'>", $list);
assertType("array{'A', 'C', 'B'}", $list);
assertType('bool', array_is_list($list));
}

public function sayHello6(): void
Expand All @@ -47,7 +53,8 @@ public function sayHello6(): void
uasort($list, function () {

});
assertType("non-empty-array<0|1|2, 'A'|'B'|'C'>", $list);
assertType("array{'A', 'C', 'B'}", $list);
assertType('bool', array_is_list($list));
}

public function sayHello7(): void
Expand All @@ -56,14 +63,16 @@ public function sayHello7(): void
uksort($list, function () {

});
assertType("non-empty-array<0|1|2, 'A'|'B'|'C'>", $list);
assertType("array{'A', 'C', 'B'}", $list);
assertType('bool', array_is_list($list));
}

public function sayHello8(): void
{
$list = ['A', 'C', 'B'];
krsort($list);
assertType("non-empty-array<0|1|2, 'A'|'B'|'C'>", $list);
assertType("array{'A', 'C', 'B'}", $list);
assertType('bool', array_is_list($list));
}

/**
Expand All @@ -75,4 +84,12 @@ public function sayHello9(array $list): void
krsort($list);
assertType("array<int<0, max>, string>", $list);
}

public function sayHello10(): void
{
$list = ['a' => 'A', 'c' => 'C', 'b' => 'B'];
krsort($list);
assertType("array{a: 'A', c: 'C', b: 'B'}", $list);
assertType('false', array_is_list($list));
}
}
5 changes: 3 additions & 2 deletions tests/PHPStan/Analyser/data/param-out.php
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ function foo15() {
$manifest,
"fooCompare"
);
assertType('non-empty-array<0|1|2, 1|2|3>', $manifest);
assertType('array{1, 2, 3}', $manifest);
}

function fooSpaceship (string $a, string $b): int {
Expand All @@ -234,7 +234,7 @@ function foo16() {
$array,
"fooSpaceship"
);
assertType('non-empty-array<0|1, 1|2>', $array);
assertType('array{1, 2}', $array);
}

function fooShuffle() {
Expand All @@ -251,6 +251,7 @@ function fooSort() {
$array = ["foo" => 123, "bar" => 456];
sort($array);
assertType('non-empty-list<123|456>', $array);
assertType('true', array_is_list($array));

$emptyArray = [];
sort($emptyArray);
Expand Down

0 comments on commit 0977a7b

Please sign in to comment.