Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/1.12.x' into 2.1.x
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Jan 15, 2025
2 parents f25c00e + d58874e commit 0b4e510
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 28 deletions.
12 changes: 0 additions & 12 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -1167,12 +1167,6 @@ parameters:
count: 3
path: src/Type/Generic/TemplateIntersectionType.php

-
message: '#^Instanceof between PHPStan\\Type\\Type and PHPStan\\Type\\IntersectionType will always evaluate to false\.$#'
identifier: instanceof.alwaysFalse
count: 2
path: src/Type/Generic/TemplateIntersectionType.php

-
message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#'
identifier: phpstanApi.instanceofType
Expand Down Expand Up @@ -1293,12 +1287,6 @@ parameters:
count: 3
path: src/Type/Generic/TemplateUnionType.php

-
message: '#^Instanceof between PHPStan\\Type\\Type and PHPStan\\Type\\UnionType will always evaluate to false\.$#'
identifier: instanceof.alwaysFalse
count: 2
path: src/Type/Generic/TemplateUnionType.php

-
message: '#^Doing instanceof PHPStan\\Type\\ConstantScalarType is error\-prone and deprecated\. Use Type\:\:isConstantScalarValue\(\) or Type\:\:getConstantScalarTypes\(\) or Type\:\:getConstantScalarValues\(\) instead\.$#'
identifier: phpstanApi.instanceofType
Expand Down
7 changes: 5 additions & 2 deletions src/Analyser/TypeSpecifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -155,14 +155,17 @@ public function specifyTypesInCondition(
}

$classType = $scope->getType($expr->class);
$type = TypeTraverser::map($classType, static function (Type $type, callable $traverse): Type {
$uncertainty = false;
$type = TypeTraverser::map($classType, static function (Type $type, callable $traverse) use (&$uncertainty): Type {
if ($type instanceof UnionType || $type instanceof IntersectionType) {
return $traverse($type);
}
if ($type->getObjectClassNames() !== []) {
$uncertainty = true;
return $type;
}
if ($type instanceof GenericClassStringType) {
$uncertainty = true;
return $type->getGenericType();
}
if ($type instanceof ConstantStringType) {
Expand All @@ -178,7 +181,7 @@ public function specifyTypesInCondition(
new ObjectWithoutClassType(),
);
return $this->create($exprNode, $type, $context, $scope)->setRootExpr($expr);
} elseif ($context->false()) {
} elseif ($context->false() && !$uncertainty) {
$exprType = $scope->getType($expr->expr);
if (!$type->isSuperTypeOf($exprType)->yes()) {
return $this->create($exprNode, $type, $context, $scope)->setRootExpr($expr);
Expand Down
43 changes: 43 additions & 0 deletions tests/PHPStan/Analyser/nsrt/bug-12107.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php declare(strict_types = 1);

namespace Bug12107;

use LogicException;
use Throwable;

use function PHPStan\Testing\assertType;

class HelloWorld
{
public function sayHello(Throwable $e1, LogicException $e2): void
{
if ($e1 instanceof $e2) {
return;
}

assertType('Throwable', $e1);
assertType('bool', $e1 instanceof $e2); // could be false
}

/** @param class-string<LogicException> $e2 */
public function sayHello2(Throwable $e1, string $e2): void
{
if ($e1 instanceof $e2) {
return;
}


assertType('Throwable', $e1);
assertType('bool', $e1 instanceof $e2); // could be false
}

public function sayHello3(Throwable $e1): void
{
if ($e1 instanceof LogicException) {
return;
}

assertType('Throwable~LogicException', $e1);
assertType('false', $e1 instanceof LogicException);
}
}
2 changes: 1 addition & 1 deletion tests/PHPStan/Analyser/nsrt/instanceof-class-string.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public function doBar(Foo $foo, Bar $bar): void
if ($foo instanceof $class) {
assertType(self::class, $foo);
} else {
assertType('InstanceOfClassString\Foo~InstanceOfClassString\Bar', $foo);
assertType('InstanceOfClassString\Foo', $foo);
}
}

Expand Down
16 changes: 8 additions & 8 deletions tests/PHPStan/Analyser/nsrt/instanceof.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ public function testExprInstanceof($subject, string $classString, $union, $inter
assertType('true', $subject instanceof Foo);
assertType('bool', $subject instanceof $classString);
} else {
assertType('mixed~InstanceOfNamespace\Foo', $subject);
assertType('false', $subject instanceof Foo);
assertType('false', $subject instanceof $classString);
assertType('mixed', $subject);
assertType('bool', $subject instanceof Foo);
assertType('bool', $subject instanceof $classString); // could be false
}

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

if ($subject instanceof $objectTString) {
assertType('ObjectT of InstanceOfNamespace\BarInterface (method InstanceOfNamespace\Foo::testExprInstanceof(), argument)', $subject);
assertType('bool', $subject instanceof $objectTString);
} else {
assertType('mixed~ObjectT of InstanceOfNamespace\BarInterface (method InstanceOfNamespace\Foo::testExprInstanceof(), argument)', $subject);
assertType('mixed', $subject);
assertType('bool', $subject instanceof $objectTString); // can be false
}

if ($subject instanceof $mixedTString) {
assertType('MixedT (method InstanceOfNamespace\Foo::testExprInstanceof(), argument)&object', $subject);
assertType('bool', $subject instanceof $mixedTString);
} else {
assertType('mixed~MixedT (method InstanceOfNamespace\Foo::testExprInstanceof(), argument)', $subject);
assertType('mixed', $subject);
assertType('bool', $subject instanceof $mixedTString); // can be false
}

Expand Down Expand Up @@ -180,8 +180,8 @@ public function testExprInstanceof($subject, string $classString, $union, $inter
assertType('InstanceOfNamespace\Foo', $object);
assertType('bool', $object instanceof $classString);
} else {
assertType('object~InstanceOfNamespace\Foo', $object);
assertType('false', $object instanceof $classString);
assertType('object', $object);
assertType('bool', $object instanceof $classString); // could be false
}

if ($instance instanceof $string) {
Expand Down
5 changes: 0 additions & 5 deletions tests/PHPStan/Rules/Classes/ImpossibleInstanceOfRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,6 @@ public function testInstanceof(): void
388,
$tipText,
],
[
'Instanceof between T of Exception and Error will always evaluate to false.',
404,
$tipText,
],
[
'Instanceof between class-string<DateTimeInterface> and DateTimeInterface will always evaluate to false.',
418,
Expand Down

0 comments on commit 0b4e510

Please sign in to comment.