Skip to content

Commit

Permalink
Improve non strict in array
Browse files Browse the repository at this point in the history
  • Loading branch information
VincentLanglet authored and ondrejmirtes committed Aug 13, 2024
1 parent 708d938 commit 34d74e8
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 10 deletions.
27 changes: 17 additions & 10 deletions src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace PHPStan\Type\Php;

use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\BinaryOp\Equal;
use PhpParser\Node\Expr\BinaryOp\Identical;
use PhpParser\Node\Expr\FuncCall;
use PHPStan\Analyser\Scope;
Expand Down Expand Up @@ -52,7 +53,16 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n

$needleExpr = $node->getArgs()[0]->value;
$arrayExpr = $node->getArgs()[1]->value;
if ($arrayExpr instanceof Array_ && $isStrictComparison) {

$needleType = $scope->getType($needleExpr);
$arrayType = $scope->getType($arrayExpr);
$arrayValueType = $arrayType->getIterableValueType();

$isStrictComparison = $isStrictComparison
|| $needleType->isEnum()->yes()
|| $arrayValueType->isEnum()->yes();

if ($arrayExpr instanceof Array_) {
$types = null;
foreach ($arrayExpr->items as $item) {
if ($item === null) {
Expand All @@ -62,7 +72,12 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n
$types = null;
break;
}
$itemTypes = $this->typeSpecifier->resolveIdentical(new Identical($needleExpr, $item->value), $scope, $context, null);

if ($isStrictComparison) {
$itemTypes = $this->typeSpecifier->resolveIdentical(new Identical($needleExpr, $item->value), $scope, $context, null);
} else {
$itemTypes = $this->typeSpecifier->resolveEqual(new Equal($needleExpr, $item->value), $scope, $context, null);
}

if ($types === null) {
$types = $itemTypes;
Expand All @@ -77,14 +92,6 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n
}
}

$needleType = $scope->getType($needleExpr);
$arrayType = $scope->getType($arrayExpr);
$arrayValueType = $arrayType->getIterableValueType();

$isStrictComparison = $isStrictComparison
|| $needleType->isEnum()->yes()
|| $arrayValueType->isEnum()->yes();

if (!$isStrictComparison) {
if (
$context->true()
Expand Down
48 changes: 48 additions & 0 deletions tests/PHPStan/Analyser/nsrt/in_array_loose.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

namespace InArrayLoose;

use function PHPStan\Testing\assertType;

class Foo
{
public function looseComparison(
string $string,
int $int,
float $float,
bool $bool,
string|int $stringOrInt,
string|null $stringOrNull,
): void {
if (in_array($string, ['1', 'a'])) {
assertType("'1'|'a'", $string);
}
if (in_array($string, [1, 'a'])) {
assertType("string", $string); // could be '1'|'a'
}
if (in_array($int, [1, 2])) {
assertType('1|2', $int);
}
if (in_array($int, ['1', 2])) {
assertType('int', $int); // could be 1|2
}
if (in_array($bool, [true])) {
assertType('true', $bool);
}
if (in_array($bool, [true, null])) {
assertType('bool', $bool);
}
if (in_array($float, [1.0, 2.0])) {
assertType('1.0|2.0', $float);
}
if (in_array($float, ['1', 2.0])) {
assertType('float', $float); // could be 1.0|2.0
}
if (in_array($stringOrInt, ['1', '2'])) {
assertType('int|string', $stringOrInt); // could be '1'|'2'|1|2
}
if (in_array($stringOrNull, ['1', 'a'])) {
assertType('string|null', $stringOrNull); // could be '1'|'a'
}
}
}
9 changes: 9 additions & 0 deletions tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -590,4 +590,13 @@ public function testBug11313(): void
$this->analyse([__DIR__ . '/data/bug-11313.php'], []);
}

public function testBug9436(): void
{
if (PHP_VERSION_ID < 80000) {
$this->markTestSkipped('Test requires PHP 8.0.');
}

$this->analyse([__DIR__ . '/data/bug-9436.php'], []);
}

}
15 changes: 15 additions & 0 deletions tests/PHPStan/Rules/Comparison/data/bug-9436.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php // lint >= 8.0

namespace Bug9436;

$foo = rand(0, 100);

if (!in_array($foo, [0, 1, 2])) {
exit();
}

$bar = match ($foo) {
0 => 'a',
1 => 'b',
2 => 'c',
};

0 comments on commit 34d74e8

Please sign in to comment.