Skip to content

Commit

Permalink
Improve loose comparison on intersection type
Browse files Browse the repository at this point in the history
  • Loading branch information
staabm committed Dec 22, 2024
1 parent 33ff84d commit ab4ccd0
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 16 deletions.
12 changes: 12 additions & 0 deletions src/TrinaryLogic.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ public static function createFromBoolean(bool $value): self
return self::$registry[$yesNo] ??= new self($yesNo);
}

public static function createFromBooleanType(BooleanType $type): self
{
if ($type->isTrue()->yes()) {
return self::createYes();
}
if ($type->isFalse()->yes()) {
return self::createNo();
}

return self::createMaybe();
}

private static function create(int $value): self
{
self::$registry[$value] ??= new self($value);
Expand Down
1 change: 1 addition & 0 deletions src/Type/Accessory/AccessoryLowercaseStringType.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use PHPStan\Type\BooleanType;
use PHPStan\Type\CompoundType;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\Constant\ConstantIntegerType;
use PHPStan\Type\ErrorType;
use PHPStan\Type\FloatType;
Expand Down
4 changes: 4 additions & 0 deletions src/Type/Accessory/AccessoryNonEmptyStringType.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use PHPStan\Type\BooleanType;
use PHPStan\Type\CompoundType;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\Constant\ConstantIntegerType;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\ErrorType;
Expand Down Expand Up @@ -322,6 +323,9 @@ public function isScalar(): TrinaryLogic

public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType
{
if ($type->isString()->yes() && $type->isNonEmptyString()->no()) {
return new ConstantBooleanType(false);
}
return new BooleanType();
}

Expand Down
1 change: 1 addition & 0 deletions src/Type/Accessory/AccessoryUppercaseStringType.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use PHPStan\Type\BooleanType;
use PHPStan\Type\CompoundType;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\Constant\ConstantIntegerType;
use PHPStan\Type\ErrorType;
use PHPStan\Type\FloatType;
Expand Down
4 changes: 3 additions & 1 deletion src/Type/IntersectionType.php
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,9 @@ public function isScalar(): TrinaryLogic

public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType
{
return new BooleanType();
return $this->intersectResults(
static fn (Type $innerType): TrinaryLogic => TrinaryLogic::createFromBooleanType($innerType->looseCompare($type, $phpVersion))
)->toBooleanType();
}

public function isOffsetAccessible(): TrinaryLogic
Expand Down
18 changes: 3 additions & 15 deletions src/Type/UnionType.php
Original file line number Diff line number Diff line change
Expand Up @@ -676,21 +676,9 @@ public function isScalar(): TrinaryLogic

public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType
{
$lastResult = null;
foreach ($this->types as $innerType) {
$result = $innerType->looseCompare($type, $phpVersion);
if ($lastResult === null) {
$lastResult = $result;
continue;
}
if ($lastResult->equals($result)) {
continue;
}

return new BooleanType();
}

return $lastResult ?? new BooleanType();
return $this->unionResults(
static fn (Type $innerType): TrinaryLogic => TrinaryLogic::createFromBooleanType($innerType->looseCompare($type, $phpVersion))
)->toBooleanType();
}

public function isOffsetAccessible(): TrinaryLogic
Expand Down
36 changes: 36 additions & 0 deletions tests/PHPStan/Analyser/nsrt/loose-comparisons.php
Original file line number Diff line number Diff line change
Expand Up @@ -698,4 +698,40 @@ public function sayConstUnion(
assertType('bool', $constMix == $looseZero);
}

/**
* @param uppercase-string $upper
* @param lowercase-string $lower
*/
public function sayIntersection(
string $upper,
string $lower,
string $s,
): void
{
assertType('bool', '' == $upper);
if ($upper != '') {
assertType('false', '' == $upper);
}
assertType('bool', '0' == $upper);
assertType('bool', 'a' == $upper); // should be false
assertType('bool', 'abc' == $upper); // should be false
assertType('bool', 'aBc' == $upper);
assertType('bool', strtoupper($s) == $upper);
assertType('bool', strtolower($s) == $upper); // should be false
assertType('bool', $upper == $lower); // should be false

assertType('bool', '' == $lower);
if ($lower != '') {
assertType('false', '' == $lower);
}
assertType('bool', '0' == $lower);
assertType('bool', 'A' == $lower); // should be false
assertType('bool', 'ABC' == $lower); // should be false
assertType('bool', 'AbC' == $lower);
assertType('bool', strtoupper($s) == $lower); // should be false
assertType('bool', strtolower($s) == $lower);
assertType('bool', $lower == $upper); // should be false
}


}

0 comments on commit ab4ccd0

Please sign in to comment.