Skip to content

Commit

Permalink
Fix return type of array_search() with constant array type haystack
Browse files Browse the repository at this point in the history
  • Loading branch information
takaram committed Oct 12, 2022
1 parent b1b0dc9 commit cb14292
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 12 deletions.
15 changes: 3 additions & 12 deletions src/Type/Php/ArraySearchFunctionDynamicReturnTypeExtension.php
Expand Up @@ -11,7 +11,6 @@
use PHPStan\Type\ConstantScalarType;
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
use PHPStan\Type\NullType;
use PHPStan\Type\ObjectWithoutClassType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;
use PHPStan\Type\TypeUtils;
Expand Down Expand Up @@ -93,33 +92,25 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
private function resolveTypeFromConstantHaystackAndNeedle(Type $needle, ConstantArrayType $haystack): Type
{
$matchesByType = [];
$hasIdenticalValue = false;

foreach ($haystack->getValueTypes() as $index => $valueType) {
$isNeedleSuperType = $valueType->isSuperTypeOf($needle);
if ($isNeedleSuperType->no()) {
$matchesByType[] = new ConstantBooleanType(false);
continue;
}

if ($needle instanceof ConstantScalarType && $valueType instanceof ConstantScalarType
&& $needle->getValue() === $valueType->getValue()
) {
return $haystack->getKeyTypes()[$index];
$hasIdenticalValue = true;
}

$matchesByType[] = $haystack->getKeyTypes()[$index];
if (!$isNeedleSuperType->maybe()) {
continue;
}

$matchesByType[] = new ConstantBooleanType(false);
}

if (count($matchesByType) > 0) {
if (
$haystack->getIterableValueType()->accepts($needle, true)->yes()
&& $needle->isSuperTypeOf(new ObjectWithoutClassType())->no()
) {
if ($hasIdenticalValue) {
return TypeCombinator::union(...$matchesByType);
}

Expand Down
1 change: 1 addition & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Expand Up @@ -1055,6 +1055,7 @@ public function dataFileAsserts(): iterable
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-8008.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-5552.php');
yield from $this->gatherAssertTypes(__DIR__ . '/../Rules/Properties/data/bug-7839.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-3789.php');
}

/**
Expand Down
17 changes: 17 additions & 0 deletions tests/PHPStan/Analyser/data/bug-3789.php
@@ -0,0 +1,17 @@
<?php

namespace Bug3789;

use function PHPStan\Testing\assertType;

/**
* @param array{string, string, string} $haystack
*/
function doFoo(string $needle, array $haystack): void {
assertType('0|1|2|false', array_search($needle, $haystack, true));
assertType('0|1|2|false', array_search('foo', $haystack, true));

$haystack[1] = 'foo';
assertType('0|1|2|false', array_search($needle, $haystack, true));
assertType('0|1|2', array_search('foo', $haystack, true));
}

0 comments on commit cb14292

Please sign in to comment.