Skip to content

Commit 33ff84d

Browse files
committed
Improve loose comparison on union type
1 parent aa4a123 commit 33ff84d

File tree

3 files changed

+60
-3
lines changed

3 files changed

+60
-3
lines changed

src/Type/UnionType.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,21 @@ public function isScalar(): TrinaryLogic
676676

677677
public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType
678678
{
679-
return new BooleanType();
679+
$lastResult = null;
680+
foreach ($this->types as $innerType) {
681+
$result = $innerType->looseCompare($type, $phpVersion);
682+
if ($lastResult === null) {
683+
$lastResult = $result;
684+
continue;
685+
}
686+
if ($lastResult->equals($result)) {
687+
continue;
688+
}
689+
690+
return new BooleanType();
691+
}
692+
693+
return $lastResult ?? new BooleanType();
680694
}
681695

682696
public function isOffsetAccessible(): TrinaryLogic

tests/PHPStan/Analyser/nsrt/loose-comparisons.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,4 +653,49 @@ public function sayInt(
653653

654654
}
655655

656+
/**
657+
* @param true|1|"1" $looseOne
658+
* @param false|0|"0" $looseZero
659+
* @param false|1 $constMix
660+
*/
661+
public function sayConstUnion(
662+
$looseOne,
663+
$looseZero,
664+
$constMix
665+
): void
666+
{
667+
assertType('true', $looseOne == 1);
668+
assertType('false', $looseOne == 0);
669+
assertType('true', $looseOne == true);
670+
assertType('false', $looseOne == false);
671+
assertType('true', $looseOne == "1");
672+
assertType('false', $looseOne == "0");
673+
assertType('false', $looseOne == []);
674+
675+
assertType('false', $looseZero == 1);
676+
assertType('true', $looseZero == 0);
677+
assertType('false', $looseZero == true);
678+
assertType('true', $looseZero == false);
679+
assertType('false', $looseZero == "1");
680+
assertType('true', $looseZero == "0");
681+
assertType('bool', $looseZero == []);
682+
683+
assertType('bool', $constMix == 0);
684+
assertType('bool', $constMix == 1);
685+
assertType('bool', $constMix == true);
686+
assertType('bool', $constMix == false);
687+
assertType('bool', $constMix == "1");
688+
assertType('bool', $constMix == "0");
689+
assertType('bool', $constMix == []);
690+
691+
assertType('true', $looseOne == $looseOne);
692+
assertType('true', $looseZero == $looseZero);
693+
assertType('false', $looseOne == $looseZero);
694+
assertType('false', $looseZero == $looseOne);
695+
assertType('bool', $looseOne == $constMix);
696+
assertType('bool', $constMix == $looseOne);
697+
assertType('bool', $looseZero == $constMix);
698+
assertType('bool', $constMix == $looseZero);
699+
}
700+
656701
}

tests/PHPStan/Rules/Comparison/ConstantLooseComparisonRuleTest.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,12 +181,10 @@ public function testBug11694(): void
181181
[
182182
"Loose comparison using == between '13foo' and int<10, 20> will always evaluate to false.",
183183
29,
184-
'Because the type is coming from a PHPDoc, you can turn off this check by setting <fg=cyan>treatPhpDocTypesAsCertain: false</> in your <fg=cyan>%configurationFile%</>.',
185184
],
186185
[
187186
"Loose comparison using == between int<10, 20> and '13foo' will always evaluate to false.",
188187
30,
189-
'Because the type is coming from a PHPDoc, you can turn off this check by setting <fg=cyan>treatPhpDocTypesAsCertain: false</> in your <fg=cyan>%configurationFile%</>.',
190188
],
191189
]);
192190
}

0 commit comments

Comments
 (0)