Skip to content

Commit b439fed

Browse files
committed
Fix StaticType::isSuperTypeOf() for subtypes of ObjectType
1 parent 307176a commit b439fed

File tree

6 files changed

+75
-11
lines changed

6 files changed

+75
-11
lines changed

phpstan-baseline.neon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1450,7 +1450,7 @@ parameters:
14501450

14511451
-
14521452
message: "#^Doing instanceof PHPStan\\\\Type\\\\ObjectType is error\\-prone and deprecated\\. Use Type\\:\\:isObject\\(\\) or Type\\:\\:getObjectClassNames\\(\\) instead\\.$#"
1453-
count: 3
1453+
count: 2
14541454
path: src/Type/StaticType.php
14551455

14561456
-

src/Reflection/Native/NativeMethodReflection.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,10 @@ public function getPrototype(): ClassMemberReflection
6565
{
6666
try {
6767
$prototypeMethod = $this->reflection->getPrototype();
68-
$prototypeDeclaringClass = $this->reflectionProvider->getClass($prototypeMethod->getDeclaringClass()->getName());
68+
$prototypeDeclaringClass = $this->declaringClass->getAncestorWithClassName($prototypeMethod->getDeclaringClass()->getName());
69+
if ($prototypeDeclaringClass === null) {
70+
$prototypeDeclaringClass = $this->reflectionProvider->getClass($prototypeMethod->getDeclaringClass()->getName());
71+
}
6972

7073
$tentativeReturnType = null;
7174
if ($prototypeMethod->getTentativeReturnType() !== null) {

src/Reflection/Php/PhpMethodReflection.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,10 @@ public function getPrototype(): ClassMemberReflection
104104
{
105105
try {
106106
$prototypeMethod = $this->reflection->getPrototype();
107-
$prototypeDeclaringClass = $this->reflectionProvider->getClass($prototypeMethod->getDeclaringClass()->getName());
107+
$prototypeDeclaringClass = $this->declaringClass->getAncestorWithClassName($prototypeMethod->getDeclaringClass()->getName());
108+
if ($prototypeDeclaringClass === null) {
109+
$prototypeDeclaringClass = $this->reflectionProvider->getClass($prototypeMethod->getDeclaringClass()->getName());
110+
}
108111

109112
$tentativeReturnType = null;
110113
if ($prototypeMethod->getTentativeReturnType() !== null) {

src/Type/StaticType.php

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,6 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult
149149

150150
public function isSuperTypeOf(Type $type): TrinaryLogic
151151
{
152-
if ($type instanceof ObjectType) {
153-
$classReflection = $type->getClassReflection();
154-
if ($classReflection !== null && $classReflection->isFinal()) {
155-
$type = new StaticType($classReflection, $type->getSubtractedType());
156-
}
157-
}
158-
159152
if ($type instanceof self) {
160153
return $this->getStaticObjectType()->isSuperTypeOf($type);
161154
}
@@ -165,7 +158,15 @@ public function isSuperTypeOf(Type $type): TrinaryLogic
165158
}
166159

167160
if ($type instanceof ObjectType) {
168-
return $this->getStaticObjectType()->isSuperTypeOf($type)->and(TrinaryLogic::createMaybe());
161+
$result = $this->getStaticObjectType()->isSuperTypeOf($type);
162+
if ($result->yes()) {
163+
$classReflection = $type->getClassReflection();
164+
if ($classReflection !== null && $classReflection->isFinal()) {
165+
return $result;
166+
}
167+
}
168+
169+
return $result->and(TrinaryLogic::createMaybe());
169170
}
170171

171172
if ($type instanceof CompoundType) {

tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -963,4 +963,23 @@ public function testEnumTips(): void
963963
]);
964964
}
965965

966+
public function testBug9142(): void
967+
{
968+
if (PHP_VERSION_ID < 80100) {
969+
$this->markTestSkipped('Test requires PHP 8.1.');
970+
}
971+
972+
$this->checkAlwaysTrueStrictComparison = true;
973+
$this->analyse([__DIR__ . '/data/bug-9142.php'], [
974+
[
975+
'Strict comparison using === between $this(Bug9142\MyEnum) and Bug9142\MyEnum::Three will always evaluate to false.',
976+
18,
977+
],
978+
[
979+
'Strict comparison using === between Bug9142\MyEnum and Bug9142\MyEnum::Three will always evaluate to false.',
980+
31,
981+
],
982+
]);
983+
}
984+
966985
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php // lint >= 8.1
2+
3+
namespace Bug9142;
4+
5+
enum MyEnum: string
6+
{
7+
8+
case One = 'one';
9+
case Two = 'two';
10+
case Three = 'three';
11+
12+
public function thisTypeWithSubtractedEnumCase(): int
13+
{
14+
if ($this === self::Three) {
15+
return -1;
16+
}
17+
18+
if ($this === self::Three) {
19+
return 0;
20+
}
21+
22+
return 1;
23+
}
24+
25+
public function enumTypeWithSubtractedEnumCase(self $self): int
26+
{
27+
if ($self === self::Three) {
28+
return -1;
29+
}
30+
31+
if ($self === self::Three) {
32+
return 0;
33+
}
34+
35+
return 1;
36+
}
37+
38+
}

0 commit comments

Comments
 (0)