Skip to content

Commit 01e5828

Browse files
Solve identical comparison with call-site variance
1 parent 322de33 commit 01e5828

File tree

5 files changed

+75
-2
lines changed

5 files changed

+75
-2
lines changed

Diff for: src/Reflection/InitializerExprTypeResolver.php

+7-2
Original file line numberDiff line numberDiff line change
@@ -1336,6 +1336,10 @@ public function getShiftRightType(Expr $left, Expr $right, callable $getTypeCall
13361336

13371337
public function resolveIdenticalType(Type $leftType, Type $rightType): BooleanType
13381338
{
1339+
if ($leftType instanceof NeverType || $rightType instanceof NeverType) {
1340+
return new ConstantBooleanType(false);
1341+
}
1342+
13391343
if ($leftType instanceof ConstantScalarType && $rightType instanceof ConstantScalarType) {
13401344
return new ConstantBooleanType($leftType->getValue() === $rightType->getValue());
13411345
}
@@ -1346,8 +1350,9 @@ public function resolveIdenticalType(Type $leftType, Type $rightType): BooleanTy
13461350
return new ConstantBooleanType($leftTypeFiniteTypes[0]->equals($rightTypeFiniteType[0]));
13471351
}
13481352

1349-
$isSuperset = $leftType->isSuperTypeOf($rightType);
1350-
if ($isSuperset->no()) {
1353+
$isLeftSupertype = $leftType->isSuperTypeOf($rightType);
1354+
$isRightSupertype = $rightType->isSuperTypeOf($leftType);
1355+
if ($isLeftSupertype->no() && $isRightSupertype->no()) {
13511356
return new ConstantBooleanType(false);
13521357
}
13531358

Diff for: src/Type/Enum/EnumCaseObjectType.php

+11
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use PHPStan\Type\Constant\ConstantStringType;
1818
use PHPStan\Type\GeneralizePrecision;
1919
use PHPStan\Type\ObjectType;
20+
use PHPStan\Type\SubtractableType;
2021
use PHPStan\Type\Type;
2122
use PHPStan\Type\VerbosityLevel;
2223
use function sprintf;
@@ -79,6 +80,16 @@ public function isSuperTypeOf(Type $type): TrinaryLogic
7980
return $type->isSubTypeOf($this);
8081
}
8182

83+
if (
84+
$type instanceof SubtractableType
85+
&& $type->getSubtractedType() !== null
86+
) {
87+
$isSuperType = $type->getSubtractedType()->isSuperTypeOf($this);
88+
if ($isSuperType->yes()) {
89+
return TrinaryLogic::createNo();
90+
}
91+
}
92+
8293
$parent = new parent($this->getClassName(), $this->getSubtractedType(), $this->getClassReflection());
8394

8495
return $parent->isSuperTypeOf($type)->and(TrinaryLogic::createMaybe());

Diff for: tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php

+12
Original file line numberDiff line numberDiff line change
@@ -1040,4 +1040,16 @@ public function testBug9804(): void
10401040
$this->analyse([__DIR__ . '/data/bug-9804.php'], []);
10411041
}
10421042

1043+
public function testBug11161(): void
1044+
{
1045+
$this->checkAlwaysTrueStrictComparison = true;
1046+
$this->analyse([__DIR__ . '/data/bug-11161.php'], []);
1047+
}
1048+
1049+
public function testBug10697(): void
1050+
{
1051+
$this->checkAlwaysTrueStrictComparison = true;
1052+
$this->analyse([__DIR__ . '/data/bug-10697.php'], []);
1053+
}
1054+
10431055
}

Diff for: tests/PHPStan/Rules/Comparison/data/bug-10697.php

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Bug10697;
4+
5+
/** @template T */
6+
abstract class HelloWorld
7+
{
8+
public static function foo(): void
9+
{
10+
if (self::class === static::class) {}
11+
}
12+
}

Diff for: tests/PHPStan/Rules/Comparison/data/bug-11161.php

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Bug11161;
4+
5+
/** @template ItemType */
6+
interface Collection
7+
{
8+
/** @param ItemType $item */
9+
public function add(mixed $item): void;
10+
11+
/** @return ItemType|null */
12+
public function get(int $index): mixed;
13+
}
14+
15+
class Comparator
16+
{
17+
/**
18+
* @param Collection<object> $foo1
19+
* @param Collection<covariant object> $foo2
20+
*/
21+
public static function compare(Collection $foo1, Collection $foo2): bool
22+
{
23+
return $foo1 === $foo2;
24+
}
25+
}
26+
27+
/**
28+
* @param Collection<object> $collection
29+
*/
30+
function test(Collection $collection): bool
31+
{
32+
return Comparator::compare($collection, $collection);
33+
}

0 commit comments

Comments
 (0)