Skip to content

Commit 2d15649

Browse files
committed
Improve loose comparison on intersection type
1 parent 33ff84d commit 2d15649

File tree

6 files changed

+52
-16
lines changed

6 files changed

+52
-16
lines changed

src/TrinaryLogic.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,18 @@ public static function createFromBoolean(bool $value): self
4747
return self::$registry[$yesNo] ??= new self($yesNo);
4848
}
4949

50+
public static function createFromBooleanType(BooleanType $type): self
51+
{
52+
if ($type->isTrue()->yes()) {
53+
return self::createYes();
54+
}
55+
if ($type->isFalse()->yes()) {
56+
return self::createNo();
57+
}
58+
59+
return self::createMaybe();
60+
}
61+
5062
private static function create(int $value): self
5163
{
5264
self::$registry[$value] ??= new self($value);

src/Type/Accessory/AccessoryLowercaseStringType.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use PHPStan\Type\BooleanType;
1212
use PHPStan\Type\CompoundType;
1313
use PHPStan\Type\Constant\ConstantArrayType;
14+
use PHPStan\Type\Constant\ConstantBooleanType;
1415
use PHPStan\Type\Constant\ConstantIntegerType;
1516
use PHPStan\Type\ErrorType;
1617
use PHPStan\Type\FloatType;
@@ -326,6 +327,9 @@ public function isScalar(): TrinaryLogic
326327

327328
public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType
328329
{
330+
if ($type->isUppercaseString()->yes()) {
331+
return new ConstantBooleanType(false);
332+
}
329333
return new BooleanType();
330334
}
331335

src/Type/Accessory/AccessoryUppercaseStringType.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use PHPStan\Type\BooleanType;
1212
use PHPStan\Type\CompoundType;
1313
use PHPStan\Type\Constant\ConstantArrayType;
14+
use PHPStan\Type\Constant\ConstantBooleanType;
1415
use PHPStan\Type\Constant\ConstantIntegerType;
1516
use PHPStan\Type\ErrorType;
1617
use PHPStan\Type\FloatType;
@@ -326,6 +327,9 @@ public function isScalar(): TrinaryLogic
326327

327328
public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType
328329
{
330+
if ($type->isLowercaseString()->yes()) {
331+
return new ConstantBooleanType(false);
332+
}
329333
return new BooleanType();
330334
}
331335

src/Type/IntersectionType.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -716,7 +716,9 @@ public function isScalar(): TrinaryLogic
716716

717717
public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType
718718
{
719-
return new BooleanType();
719+
return $this->intersectResults(
720+
static fn (Type $innerType): TrinaryLogic => TrinaryLogic::createFromBooleanType($innerType->looseCompare($type, $phpVersion))
721+
)->toBooleanType();
720722
}
721723

722724
public function isOffsetAccessible(): TrinaryLogic

src/Type/UnionType.php

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

677677
public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType
678678
{
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();
679+
return $this->unionResults(
680+
static fn (Type $innerType): TrinaryLogic => TrinaryLogic::createFromBooleanType($innerType->looseCompare($type, $phpVersion))
681+
)->toBooleanType();
694682
}
695683

696684
public function isOffsetAccessible(): TrinaryLogic

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,4 +698,30 @@ public function sayConstUnion(
698698
assertType('bool', $constMix == $looseZero);
699699
}
700700

701+
/**
702+
* @param uppercase-string $upper
703+
* @param lowercase-string $lower
704+
*/
705+
public function sayIntersection(
706+
string $upper,
707+
string $lower,
708+
string $s,
709+
): void
710+
{
711+
assertType('false', 'a' == $upper);
712+
assertType('false', 'abc' == $upper);
713+
assertType('bool', 'aBc' == $upper);
714+
assertType('bool', strtoupper($s) == $upper);
715+
assertType('false', strtolower($s) == $upper);
716+
assertType('false', $upper == $lower);
717+
718+
assertType('false', 'A' == $lower);
719+
assertType('false', 'ABC' == $lower);
720+
assertType('bool', 'AbC' == $lower);
721+
assertType('false', strtoupper($s) == $lower);
722+
assertType('bool', strtolower($s) == $lower);
723+
assertType('false', $lower == $upper);
724+
}
725+
726+
701727
}

0 commit comments

Comments
 (0)