Skip to content

Commit

Permalink
Fix array_filter that does not return all items
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Sep 3, 2022
1 parent ec92402 commit 2e89a22
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use PHPStan\Type\BenevolentUnionType;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Constant\ConstantArrayTypeBuilder;
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
use PHPStan\Type\MixedType;
use PHPStan\Type\NeverType;
Expand Down Expand Up @@ -170,12 +171,12 @@ private function filterByTruthyValue(Scope $scope, Error|Variable|null $itemVar,
$builder = ConstantArrayTypeBuilder::createEmpty();
foreach ($constantArray->getKeyTypes() as $i => $keyType) {
$itemType = $constantArray->getValueTypes()[$i];
[$newKeyType, $newItemType] = $this->processKeyAndItemType($scope, $keyType, $itemType, $itemVar, $keyVar, $expr);
[$newKeyType, $newItemType, $optional] = $this->processKeyAndItemType($scope, $keyType, $itemType, $itemVar, $keyVar, $expr);
if ($newKeyType instanceof NeverType || $newItemType instanceof NeverType) {
continue;
}
if ($itemType->equals($newItemType) && $keyType->equals($newKeyType)) {
$builder->setOffsetValueType($keyType, $itemType);
$builder->setOffsetValueType($keyType, $itemType, $optional);
continue;
}

Expand All @@ -198,7 +199,7 @@ private function filterByTruthyValue(Scope $scope, Error|Variable|null $itemVar,
}

/**
* @return array{Type, Type}
* @return array{Type, Type, bool}
*/
private function processKeyAndItemType(MutatingScope $scope, Type $keyType, Type $itemType, Error|Variable|null $itemVar, Error|Variable|null $keyVar, Expr $expr): array
{
Expand All @@ -220,11 +221,13 @@ private function processKeyAndItemType(MutatingScope $scope, Type $keyType, Type
$scope = $scope->assignVariable($keyVarName, $keyType);
}

$booleanResult = $scope->getType($expr)->toBoolean();
$scope = $scope->filterByTruthyValue($expr);

return [
$keyVarName !== null ? $scope->getVariableType($keyVarName) : $keyType,
$itemVarName !== null ? $scope->getVariableType($itemVarName) : $itemType,
!$booleanResult instanceof ConstantBooleanType,
];
}

Expand Down
1 change: 1 addition & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1007,6 +1007,7 @@ public function dataFileAsserts(): iterable
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-6170.php');
yield from $this->gatherAssertTypes(__DIR__ . '/../Rules/Arrays/data/slevomat-foreach-array-key-exists-bug.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/array-key-exists.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-7909.php');
}

/**
Expand Down
10 changes: 10 additions & 0 deletions tests/PHPStan/Analyser/data/bug-7909.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Bug7909;

use function PHPStan\Testing\assertType;

function (): void {
$filenames = array_filter(['file1', 'file2'], 'file_exists');
assertType("array{0?: 'file1', 1?: 'file2'}", $filenames);
};

0 comments on commit 2e89a22

Please sign in to comment.