Skip to content

Commit 34d74e8

Browse files
VincentLangletondrejmirtes
authored andcommitted
Improve non strict in array
1 parent 708d938 commit 34d74e8

File tree

4 files changed

+89
-10
lines changed

4 files changed

+89
-10
lines changed

src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace PHPStan\Type\Php;
44

55
use PhpParser\Node\Expr\Array_;
6+
use PhpParser\Node\Expr\BinaryOp\Equal;
67
use PhpParser\Node\Expr\BinaryOp\Identical;
78
use PhpParser\Node\Expr\FuncCall;
89
use PHPStan\Analyser\Scope;
@@ -52,7 +53,16 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n
5253

5354
$needleExpr = $node->getArgs()[0]->value;
5455
$arrayExpr = $node->getArgs()[1]->value;
55-
if ($arrayExpr instanceof Array_ && $isStrictComparison) {
56+
57+
$needleType = $scope->getType($needleExpr);
58+
$arrayType = $scope->getType($arrayExpr);
59+
$arrayValueType = $arrayType->getIterableValueType();
60+
61+
$isStrictComparison = $isStrictComparison
62+
|| $needleType->isEnum()->yes()
63+
|| $arrayValueType->isEnum()->yes();
64+
65+
if ($arrayExpr instanceof Array_) {
5666
$types = null;
5767
foreach ($arrayExpr->items as $item) {
5868
if ($item === null) {
@@ -62,7 +72,12 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n
6272
$types = null;
6373
break;
6474
}
65-
$itemTypes = $this->typeSpecifier->resolveIdentical(new Identical($needleExpr, $item->value), $scope, $context, null);
75+
76+
if ($isStrictComparison) {
77+
$itemTypes = $this->typeSpecifier->resolveIdentical(new Identical($needleExpr, $item->value), $scope, $context, null);
78+
} else {
79+
$itemTypes = $this->typeSpecifier->resolveEqual(new Equal($needleExpr, $item->value), $scope, $context, null);
80+
}
6681

6782
if ($types === null) {
6883
$types = $itemTypes;
@@ -77,14 +92,6 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n
7792
}
7893
}
7994

80-
$needleType = $scope->getType($needleExpr);
81-
$arrayType = $scope->getType($arrayExpr);
82-
$arrayValueType = $arrayType->getIterableValueType();
83-
84-
$isStrictComparison = $isStrictComparison
85-
|| $needleType->isEnum()->yes()
86-
|| $arrayValueType->isEnum()->yes();
87-
8895
if (!$isStrictComparison) {
8996
if (
9097
$context->true()
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
namespace InArrayLoose;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class Foo
8+
{
9+
public function looseComparison(
10+
string $string,
11+
int $int,
12+
float $float,
13+
bool $bool,
14+
string|int $stringOrInt,
15+
string|null $stringOrNull,
16+
): void {
17+
if (in_array($string, ['1', 'a'])) {
18+
assertType("'1'|'a'", $string);
19+
}
20+
if (in_array($string, [1, 'a'])) {
21+
assertType("string", $string); // could be '1'|'a'
22+
}
23+
if (in_array($int, [1, 2])) {
24+
assertType('1|2', $int);
25+
}
26+
if (in_array($int, ['1', 2])) {
27+
assertType('int', $int); // could be 1|2
28+
}
29+
if (in_array($bool, [true])) {
30+
assertType('true', $bool);
31+
}
32+
if (in_array($bool, [true, null])) {
33+
assertType('bool', $bool);
34+
}
35+
if (in_array($float, [1.0, 2.0])) {
36+
assertType('1.0|2.0', $float);
37+
}
38+
if (in_array($float, ['1', 2.0])) {
39+
assertType('float', $float); // could be 1.0|2.0
40+
}
41+
if (in_array($stringOrInt, ['1', '2'])) {
42+
assertType('int|string', $stringOrInt); // could be '1'|'2'|1|2
43+
}
44+
if (in_array($stringOrNull, ['1', 'a'])) {
45+
assertType('string|null', $stringOrNull); // could be '1'|'a'
46+
}
47+
}
48+
}

tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,4 +590,13 @@ public function testBug11313(): void
590590
$this->analyse([__DIR__ . '/data/bug-11313.php'], []);
591591
}
592592

593+
public function testBug9436(): void
594+
{
595+
if (PHP_VERSION_ID < 80000) {
596+
$this->markTestSkipped('Test requires PHP 8.0.');
597+
}
598+
599+
$this->analyse([__DIR__ . '/data/bug-9436.php'], []);
600+
}
601+
593602
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php // lint >= 8.0
2+
3+
namespace Bug9436;
4+
5+
$foo = rand(0, 100);
6+
7+
if (!in_array($foo, [0, 1, 2])) {
8+
exit();
9+
}
10+
11+
$bar = match ($foo) {
12+
0 => 'a',
13+
1 => 'b',
14+
2 => 'c',
15+
};

0 commit comments

Comments
 (0)