Skip to content

Commit

Permalink
Solve identical comparison with call-site variance
Browse files Browse the repository at this point in the history
  • Loading branch information
VincentLanglet authored Jun 17, 2024
1 parent 322de33 commit 01e5828
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 2 deletions.
9 changes: 7 additions & 2 deletions src/Reflection/InitializerExprTypeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -1336,6 +1336,10 @@ public function getShiftRightType(Expr $left, Expr $right, callable $getTypeCall

public function resolveIdenticalType(Type $leftType, Type $rightType): BooleanType
{
if ($leftType instanceof NeverType || $rightType instanceof NeverType) {
return new ConstantBooleanType(false);
}

if ($leftType instanceof ConstantScalarType && $rightType instanceof ConstantScalarType) {
return new ConstantBooleanType($leftType->getValue() === $rightType->getValue());
}
Expand All @@ -1346,8 +1350,9 @@ public function resolveIdenticalType(Type $leftType, Type $rightType): BooleanTy
return new ConstantBooleanType($leftTypeFiniteTypes[0]->equals($rightTypeFiniteType[0]));
}

$isSuperset = $leftType->isSuperTypeOf($rightType);
if ($isSuperset->no()) {
$isLeftSupertype = $leftType->isSuperTypeOf($rightType);
$isRightSupertype = $rightType->isSuperTypeOf($leftType);
if ($isLeftSupertype->no() && $isRightSupertype->no()) {
return new ConstantBooleanType(false);
}

Expand Down
11 changes: 11 additions & 0 deletions src/Type/Enum/EnumCaseObjectType.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\GeneralizePrecision;
use PHPStan\Type\ObjectType;
use PHPStan\Type\SubtractableType;
use PHPStan\Type\Type;
use PHPStan\Type\VerbosityLevel;
use function sprintf;
Expand Down Expand Up @@ -79,6 +80,16 @@ public function isSuperTypeOf(Type $type): TrinaryLogic
return $type->isSubTypeOf($this);
}

if (
$type instanceof SubtractableType
&& $type->getSubtractedType() !== null
) {
$isSuperType = $type->getSubtractedType()->isSuperTypeOf($this);
if ($isSuperType->yes()) {
return TrinaryLogic::createNo();
}
}

$parent = new parent($this->getClassName(), $this->getSubtractedType(), $this->getClassReflection());

return $parent->isSuperTypeOf($type)->and(TrinaryLogic::createMaybe());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1040,4 +1040,16 @@ public function testBug9804(): void
$this->analyse([__DIR__ . '/data/bug-9804.php'], []);
}

public function testBug11161(): void
{
$this->checkAlwaysTrueStrictComparison = true;
$this->analyse([__DIR__ . '/data/bug-11161.php'], []);
}

public function testBug10697(): void
{
$this->checkAlwaysTrueStrictComparison = true;
$this->analyse([__DIR__ . '/data/bug-10697.php'], []);
}

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

namespace Bug10697;

/** @template T */
abstract class HelloWorld
{
public static function foo(): void
{
if (self::class === static::class) {}
}
}
33 changes: 33 additions & 0 deletions tests/PHPStan/Rules/Comparison/data/bug-11161.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php declare(strict_types=1);

namespace Bug11161;

/** @template ItemType */
interface Collection
{
/** @param ItemType $item */
public function add(mixed $item): void;

/** @return ItemType|null */
public function get(int $index): mixed;
}

class Comparator
{
/**
* @param Collection<object> $foo1
* @param Collection<covariant object> $foo2
*/
public static function compare(Collection $foo1, Collection $foo2): bool
{
return $foo1 === $foo2;
}
}

/**
* @param Collection<object> $collection
*/
function test(Collection $collection): bool
{
return Comparator::compare($collection, $collection);
}

0 comments on commit 01e5828

Please sign in to comment.