Skip to content

Commit 0b4e510

Browse files
committed
Merge remote-tracking branch 'origin/1.12.x' into 2.1.x
2 parents f25c00e + d58874e commit 0b4e510

File tree

6 files changed

+57
-28
lines changed

6 files changed

+57
-28
lines changed

phpstan-baseline.neon

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,12 +1167,6 @@ parameters:
11671167
count: 3
11681168
path: src/Type/Generic/TemplateIntersectionType.php
11691169

1170-
-
1171-
message: '#^Instanceof between PHPStan\\Type\\Type and PHPStan\\Type\\IntersectionType will always evaluate to false\.$#'
1172-
identifier: instanceof.alwaysFalse
1173-
count: 2
1174-
path: src/Type/Generic/TemplateIntersectionType.php
1175-
11761170
-
11771171
message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#'
11781172
identifier: phpstanApi.instanceofType
@@ -1293,12 +1287,6 @@ parameters:
12931287
count: 3
12941288
path: src/Type/Generic/TemplateUnionType.php
12951289

1296-
-
1297-
message: '#^Instanceof between PHPStan\\Type\\Type and PHPStan\\Type\\UnionType will always evaluate to false\.$#'
1298-
identifier: instanceof.alwaysFalse
1299-
count: 2
1300-
path: src/Type/Generic/TemplateUnionType.php
1301-
13021290
-
13031291
message: '#^Doing instanceof PHPStan\\Type\\ConstantScalarType is error\-prone and deprecated\. Use Type\:\:isConstantScalarValue\(\) or Type\:\:getConstantScalarTypes\(\) or Type\:\:getConstantScalarValues\(\) instead\.$#'
13041292
identifier: phpstanApi.instanceofType

src/Analyser/TypeSpecifier.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,14 +155,17 @@ public function specifyTypesInCondition(
155155
}
156156

157157
$classType = $scope->getType($expr->class);
158-
$type = TypeTraverser::map($classType, static function (Type $type, callable $traverse): Type {
158+
$uncertainty = false;
159+
$type = TypeTraverser::map($classType, static function (Type $type, callable $traverse) use (&$uncertainty): Type {
159160
if ($type instanceof UnionType || $type instanceof IntersectionType) {
160161
return $traverse($type);
161162
}
162163
if ($type->getObjectClassNames() !== []) {
164+
$uncertainty = true;
163165
return $type;
164166
}
165167
if ($type instanceof GenericClassStringType) {
168+
$uncertainty = true;
166169
return $type->getGenericType();
167170
}
168171
if ($type instanceof ConstantStringType) {
@@ -178,7 +181,7 @@ public function specifyTypesInCondition(
178181
new ObjectWithoutClassType(),
179182
);
180183
return $this->create($exprNode, $type, $context, $scope)->setRootExpr($expr);
181-
} elseif ($context->false()) {
184+
} elseif ($context->false() && !$uncertainty) {
182185
$exprType = $scope->getType($expr->expr);
183186
if (!$type->isSuperTypeOf($exprType)->yes()) {
184187
return $this->create($exprNode, $type, $context, $scope)->setRootExpr($expr);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug12107;
4+
5+
use LogicException;
6+
use Throwable;
7+
8+
use function PHPStan\Testing\assertType;
9+
10+
class HelloWorld
11+
{
12+
public function sayHello(Throwable $e1, LogicException $e2): void
13+
{
14+
if ($e1 instanceof $e2) {
15+
return;
16+
}
17+
18+
assertType('Throwable', $e1);
19+
assertType('bool', $e1 instanceof $e2); // could be false
20+
}
21+
22+
/** @param class-string<LogicException> $e2 */
23+
public function sayHello2(Throwable $e1, string $e2): void
24+
{
25+
if ($e1 instanceof $e2) {
26+
return;
27+
}
28+
29+
30+
assertType('Throwable', $e1);
31+
assertType('bool', $e1 instanceof $e2); // could be false
32+
}
33+
34+
public function sayHello3(Throwable $e1): void
35+
{
36+
if ($e1 instanceof LogicException) {
37+
return;
38+
}
39+
40+
assertType('Throwable~LogicException', $e1);
41+
assertType('false', $e1 instanceof LogicException);
42+
}
43+
}

tests/PHPStan/Analyser/nsrt/instanceof-class-string.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public function doBar(Foo $foo, Bar $bar): void
3232
if ($foo instanceof $class) {
3333
assertType(self::class, $foo);
3434
} else {
35-
assertType('InstanceOfClassString\Foo~InstanceOfClassString\Bar', $foo);
35+
assertType('InstanceOfClassString\Foo', $foo);
3636
}
3737
}
3838

tests/PHPStan/Analyser/nsrt/instanceof.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ public function testExprInstanceof($subject, string $classString, $union, $inter
8080
assertType('true', $subject instanceof Foo);
8181
assertType('bool', $subject instanceof $classString);
8282
} else {
83-
assertType('mixed~InstanceOfNamespace\Foo', $subject);
84-
assertType('false', $subject instanceof Foo);
85-
assertType('false', $subject instanceof $classString);
83+
assertType('mixed', $subject);
84+
assertType('bool', $subject instanceof Foo);
85+
assertType('bool', $subject instanceof $classString); // could be false
8686
}
8787

8888
$constantString = 'InstanceOfNamespace\BarParent';
@@ -132,23 +132,23 @@ public function testExprInstanceof($subject, string $classString, $union, $inter
132132
assertType('ObjectT of InstanceOfNamespace\BarInterface (method InstanceOfNamespace\Foo::testExprInstanceof(), argument)', $subject);
133133
assertType('bool', $subject instanceof $objectT);
134134
} else {
135-
assertType('mixed~ObjectT of InstanceOfNamespace\BarInterface (method InstanceOfNamespace\Foo::testExprInstanceof(), argument)', $subject);
135+
assertType('mixed', $subject);
136136
assertType('bool', $subject instanceof $objectT); // can be false
137137
}
138138

139139
if ($subject instanceof $objectTString) {
140140
assertType('ObjectT of InstanceOfNamespace\BarInterface (method InstanceOfNamespace\Foo::testExprInstanceof(), argument)', $subject);
141141
assertType('bool', $subject instanceof $objectTString);
142142
} else {
143-
assertType('mixed~ObjectT of InstanceOfNamespace\BarInterface (method InstanceOfNamespace\Foo::testExprInstanceof(), argument)', $subject);
143+
assertType('mixed', $subject);
144144
assertType('bool', $subject instanceof $objectTString); // can be false
145145
}
146146

147147
if ($subject instanceof $mixedTString) {
148148
assertType('MixedT (method InstanceOfNamespace\Foo::testExprInstanceof(), argument)&object', $subject);
149149
assertType('bool', $subject instanceof $mixedTString);
150150
} else {
151-
assertType('mixed~MixedT (method InstanceOfNamespace\Foo::testExprInstanceof(), argument)', $subject);
151+
assertType('mixed', $subject);
152152
assertType('bool', $subject instanceof $mixedTString); // can be false
153153
}
154154

@@ -180,8 +180,8 @@ public function testExprInstanceof($subject, string $classString, $union, $inter
180180
assertType('InstanceOfNamespace\Foo', $object);
181181
assertType('bool', $object instanceof $classString);
182182
} else {
183-
assertType('object~InstanceOfNamespace\Foo', $object);
184-
assertType('false', $object instanceof $classString);
183+
assertType('object', $object);
184+
assertType('bool', $object instanceof $classString); // could be false
185185
}
186186

187187
if ($instance instanceof $string) {

tests/PHPStan/Rules/Classes/ImpossibleInstanceOfRuleTest.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,11 +163,6 @@ public function testInstanceof(): void
163163
388,
164164
$tipText,
165165
],
166-
[
167-
'Instanceof between T of Exception and Error will always evaluate to false.',
168-
404,
169-
$tipText,
170-
],
171166
[
172167
'Instanceof between class-string<DateTimeInterface> and DateTimeInterface will always evaluate to false.',
173168
418,

0 commit comments

Comments
 (0)