Skip to content

Commit 43fca98

Browse files
phpstan-botgithub-actions[bot]claude
authored
Fix phpstan/phpstan#11054: [NAN] === mixed is always evaluated as false (#5321)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1c822e2 commit 43fca98

3 files changed

Lines changed: 78 additions & 0 deletions

File tree

src/Type/Constant/ConstantFloatType.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,15 @@ public function toArrayKey(): Type
9999
return new ConstantIntegerType((int) $this->value);
100100
}
101101

102+
public function getFiniteTypes(): array
103+
{
104+
if (is_nan($this->value)) {
105+
return [];
106+
}
107+
108+
return [$this];
109+
}
110+
102111
public function generalize(GeneralizePrecision $precision): Type
103112
{
104113
return new FloatType();

tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,4 +1161,15 @@ public function testPossiblyImpureTip(): void
11611161
]);
11621162
}
11631163

1164+
public function testBug11054(): void
1165+
{
1166+
$this->analyse([__DIR__ . '/data/bug-11054.php'], [
1167+
[
1168+
'Strict comparison using === between mixed and array{INF} will always evaluate to false.',
1169+
47,
1170+
'Type array{INF} has already been eliminated from mixed.',
1171+
],
1172+
]);
1173+
}
1174+
11641175
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug11054;
4+
5+
class XXX {
6+
public const DEF_VALUE = [NAN];
7+
public const NO_VALUE = [NAN];
8+
}
9+
10+
class YYY
11+
{
12+
public const LOSSLESS = [NAN];
13+
14+
/**
15+
* @param string|int|mixed $substituteChar
16+
*/
17+
public static function convertEncoding (
18+
string $str,
19+
string $sourceEncoding,
20+
string $targetEncoding,
21+
$substituteChar = XXX::DEF_VALUE,
22+
$defValue = XXX::NO_VALUE
23+
): string {
24+
if ($substituteChar === XXX::DEF_VALUE) { // no error expected
25+
return mb_convert_encoding($str, $targetEncoding, $sourceEncoding);
26+
}
27+
28+
if ($substituteChar === self::LOSSLESS) { // no error expected
29+
return $str;
30+
}
31+
32+
return $str;
33+
}
34+
}
35+
36+
class InfTest {
37+
public const DEF_VALUE = [INF];
38+
public const NO_VALUE = [INF];
39+
40+
/** @param mixed $v */
41+
public static function test($v): void
42+
{
43+
if ($v === self::DEF_VALUE) { // no error expected
44+
return;
45+
}
46+
47+
if ($v === self::NO_VALUE) {} // error expected - INF === INF is true, so narrowing is correct
48+
}
49+
}
50+
51+
class SimpleTest {
52+
/** @param mixed $v */
53+
public static function test($v): void
54+
{
55+
if ($v === [NAN]) {} // no error expected
56+
if ($v === [INF]) {} // no error expected
57+
}
58+
}

0 commit comments

Comments
 (0)