Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/Reflection/InitializerExprTypeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@
use function is_finite;
use function is_float;
use function is_int;
use function is_nan;
use function is_numeric;
use function is_string;
use function max;
Expand Down Expand Up @@ -1944,6 +1945,10 @@ public function resolveIdenticalType(Type $leftType, Type $rightType): TypeResul
return new TypeResult(new ConstantBooleanType(false), []);
}

if ($this->containsNan($leftType) || $this->containsNan($rightType)) {
return new TypeResult(new ConstantBooleanType(false), []);
}

if ($leftType instanceof ConstantScalarType && $rightType instanceof ConstantScalarType) {
return new TypeResult(new ConstantBooleanType($leftType->getValue() === $rightType->getValue()), []);
}
Expand Down Expand Up @@ -1972,6 +1977,10 @@ public function resolveIdenticalType(Type $leftType, Type $rightType): TypeResul
*/
public function resolveEqualType(Type $leftType, Type $rightType): TypeResult
{
if ($this->containsNan($leftType) || $this->containsNan($rightType)) {
return new TypeResult(new ConstantBooleanType(false), []);
}

if (
($leftType->isEnum()->yes() && $rightType->isTrue()->no())
|| ($rightType->isEnum()->yes() && $leftType->isTrue()->no())
Expand Down Expand Up @@ -2061,6 +2070,23 @@ private function resolveConstantArrayTypeComparison(ConstantArrayType $leftType,
return new TypeResult($resultType->toBoolean(), []);
}

private function containsNan(Type $type): bool
{
if ($type instanceof ConstantFloatType && is_nan($type->getValue())) {
return true;
}

foreach ($type->getConstantArrays() as $constantArray) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the array is array{Nan}|array{1} the egality check might be true.

We need all array to contain Nan on a non optional

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All done — both background tasks (make tests and make phpstan) completed successfully, and the fix has been pushed.

foreach ($constantArray->getValueTypes() as $valueType) {
if ($this->containsNan($valueType)) {
return true;
}
}
}

return false;
}

/**
* @param BinaryOp\Plus|BinaryOp\Minus|BinaryOp\Mul|BinaryOp\Div|BinaryOp\ShiftLeft|BinaryOp\ShiftRight $expr
*/
Expand Down
15 changes: 15 additions & 0 deletions tests/PHPStan/Rules/Comparison/ConstantLooseComparisonRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -248,4 +248,19 @@ public function testBug13098(): void
$this->analyse([__DIR__ . '/data/bug-13098.php'], []);
}

public function testBug14394(): void
{
$this->treatPhpDocTypesAsCertain = true;
$this->analyse([__DIR__ . '/data/bug-14394.php'], [
[
'Loose comparison using == between float and NAN will always evaluate to false.',
8,
],
[
'Loose comparison using == between list<mixed> and array{NAN} will always evaluate to false.',
10,
],
]);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -1164,11 +1164,37 @@ public function testPossiblyImpureTip(): void
public function testBug11054(): void
{
$this->analyse([__DIR__ . '/data/bug-11054.php'], [
[
'Strict comparison using === between mixed and array{NAN} will always evaluate to false.',
24,
],
[
'Strict comparison using === between mixed and array{NAN} will always evaluate to false.',
28,
],
[
'Strict comparison using === between mixed and array{INF} will always evaluate to false.',
47,
'Type array{INF} has already been eliminated from mixed.',
],
[
'Strict comparison using === between mixed and array{NAN} will always evaluate to false.',
55,
],
]);
}

public function testBug14394(): void
{
$this->analyse([__DIR__ . '/data/bug-14394.php'], [
[
'Strict comparison using === between float and NAN will always evaluate to false.',
9,
],
[
'Strict comparison using === between list<mixed> and array{NAN} will always evaluate to false.',
11,
],
]);
}

Expand Down
13 changes: 13 additions & 0 deletions tests/PHPStan/Rules/Comparison/data/bug-14394.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php declare(strict_types = 1);

namespace Bug14394;

class Cl {
/** @param list<mixed> $v2 */
public static function test(float $v1, array $v2): void {
if ($v1 == NAN) { echo "never reached\n"; }
if ($v1 === NAN) { echo "never reached\n"; }
if ($v2 == [NAN]) { echo "never reached\n"; }
if ($v2 === [NAN]) { echo "never reached\n"; }
}
}
Loading