Skip to content

Commit a6cec39

Browse files
committed
array_flip() for constant arrays
1 parent 899fa4e commit a6cec39

File tree

3 files changed

+48
-0
lines changed

3 files changed

+48
-0
lines changed

src/Type/Php/ArrayFlipFunctionReturnTypeExtension.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
use PHPStan\Reflection\ParametersAcceptorSelector;
99
use PHPStan\Type\Accessory\NonEmptyArrayType;
1010
use PHPStan\Type\ArrayType;
11+
use PHPStan\Type\Constant\ConstantArrayTypeBuilder;
1112
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
1213
use PHPStan\Type\Type;
1314
use PHPStan\Type\TypeCombinator;
15+
use PHPStan\Type\TypeUtils;
1416
use function count;
1517

1618
class ArrayFlipFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension
@@ -30,6 +32,25 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
3032
$array = $functionCall->getArgs()[0]->value;
3133
$argType = $scope->getType($array);
3234

35+
$constantArrays = TypeUtils::getOldConstantArrays($argType);
36+
if (count($constantArrays) > 0) {
37+
$flipped = [];
38+
foreach ($constantArrays as $constantArray) {
39+
$builder = ConstantArrayTypeBuilder::createEmpty();
40+
foreach ($constantArray->getKeyTypes() as $i => $keyType) {
41+
$valueType = $constantArray->getValueTypes()[$i];
42+
$builder->setOffsetValueType(
43+
ArrayType::castToArrayKeyType($valueType),
44+
$keyType,
45+
$constantArray->isOptionalKey($i),
46+
);
47+
}
48+
$flipped[] = $builder->getArray();
49+
}
50+
51+
return TypeCombinator::union(...$flipped);
52+
}
53+
3354
if ($argType->isArray()->yes()) {
3455
$keyType = $argType->getIterableKeyType();
3556
$itemType = $argType->getIterableValueType();

tests/PHPStan/Analyser/NodeScopeResolverTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,7 @@ public function dataFileAsserts(): iterable
995995
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-7563.php');
996996
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-7764.php');
997997
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-5845.php');
998+
yield from $this->gatherAssertTypes(__DIR__ . '/data/array-flip-constant.php');
998999
}
9991000

10001001
/**
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
namespace ArrayFlipConstantArray;
4+
5+
use function array_flip;
6+
use function PHPStan\Testing\assertType;
7+
8+
class Foo
9+
{
10+
11+
public function doFoo(): void
12+
{
13+
$allowlist = ['name', 'description', 'author', 'type', 'homepage', 'require', 'require-dev', 'stability', 'license', 'autoload'];
14+
assertType('array{name: 0, description: 1, author: 2, type: 3, homepage: 4, require: 5, require-dev: 6, stability: 7, license: 8, autoload: 9}', array_flip($allowlist));
15+
}
16+
17+
public function doOptional(): void
18+
{
19+
$allowlist = ['name', 'description', 'author', 'type', 'homepage', 'require', 'require-dev', 'stability', 'license', 'autoload'];
20+
if (rand(0, 1)) {
21+
$allowlist[] = 'config';
22+
}
23+
assertType('array{name: 0, description: 1, author: 2, type: 3, homepage: 4, require: 5, require-dev: 6, stability: 7, license: 8, autoload: 9, config?: 10}', array_flip($allowlist));
24+
}
25+
26+
}

0 commit comments

Comments
 (0)