diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 136e2023ba2..356cf2721ec 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -3580,6 +3580,18 @@ private function createConditionalExpressions( continue; } + if (array_key_exists($exprString, $theirExpressionTypes)) { + $ourType = $holder->getType(); + $theirType = $theirExpressionTypes[$exprString]->getType(); + $isSuperType = $ourType->isSuperTypeOf($theirType); + if ( + $isSuperType->yes() + || ($isSuperType->maybe() && !($ourType->isObject()->yes() && $theirType->isObject()->yes())) + ) { + continue; + } + } + $typeGuards[$exprString] = $holder; } diff --git a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php index 9020c4b3c4a..12a1c31055b 100644 --- a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php +++ b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php @@ -1506,6 +1506,12 @@ public function testBug13801(): void $this->assertNoErrors($errors); } + public function testSyliusOrderIpListener(): void + { + $errors = $this->runAnalyse(__DIR__ . '/data/sylius-order-ip-listener.php'); + $this->assertNoErrors($errors); + } + /** * @param string[]|null $allAnalysedFiles * @return list diff --git a/tests/PHPStan/Analyser/data/sylius-order-ip-listener.php b/tests/PHPStan/Analyser/data/sylius-order-ip-listener.php new file mode 100644 index 00000000000..3f16ed15fb3 --- /dev/null +++ b/tests/PHPStan/Analyser/data/sylius-order-ip-listener.php @@ -0,0 +1,30 @@ += 8.0 + +declare(strict_types = 1); + +namespace SyliusOrderIpListenerIntegration; + +interface OrderInterface {} + +class Event +{ + /** @return mixed */ + public function getSubject() + { + return new \stdClass(); + } +} + +function getOrder(Event|OrderInterface $event): OrderInterface +{ + if ($event instanceof Event) { + $order = $event->getSubject(); + assert($order instanceof OrderInterface); + } + + if ($event instanceof OrderInterface) { + $order = $event; + } + + return $order; +} diff --git a/tests/PHPStan/Analyser/nsrt/bug-10085.php b/tests/PHPStan/Analyser/nsrt/bug-10085.php new file mode 100644 index 00000000000..aa8dcc3b8a9 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-10085.php @@ -0,0 +1,28 @@ + $foo + * @param list $bar + */ + public function sayHello(array $foo, array $bar): void + { + $a = $foo; + if ($a === []) { + $a = $bar; + } + + if ($a === []) { + return; + } + + assertType('array', $foo); + } +} diff --git a/tests/PHPStan/Analyser/nsrt/bug-10843.php b/tests/PHPStan/Analyser/nsrt/bug-10843.php new file mode 100644 index 00000000000..49444f1608b --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-10843.php @@ -0,0 +1,25 @@ += 8.0 + +declare(strict_types = 1); + +namespace Bug10843; + +use function PHPStan\Testing\assertType; + +class HelloWorld +{ + public function sayHello(HelloWorld|null $date): int + { + $a = match (true) { + $date instanceof HelloWorld => 1, + default => false + }; + + if ($date instanceof HelloWorld) { + assertType('1|false', $a); + return $a; + } + + throw new \Exception('Error'); + } +} diff --git a/tests/PHPStan/Analyser/nsrt/bug-11328.php b/tests/PHPStan/Analyser/nsrt/bug-11328.php new file mode 100644 index 00000000000..09e139c540d --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-11328.php @@ -0,0 +1,33 @@ += 8.1 + +declare(strict_types = 1); + +namespace Bug11328; + +use function PHPStan\Testing\assertType; + +enum Status: string { + case Live = 's1'; + case Expired = 's2'; +} + +/** @param Status[] $statuses */ +function check(array $statuses): void { + $fromDeadline = null; + $toDeadline = null; + + if (in_array(Status::Live, $statuses, true)) { + $fromDeadline = (new \DateTimeImmutable())->setTime(23, 59, 59); + } + + assertType('DateTimeImmutable|null', $fromDeadline); + + if (in_array(Status::Expired, $statuses, true)) { + assertType('DateTimeImmutable|null', $fromDeadline); + if ($fromDeadline === null) { + $toDeadline = (new \DateTimeImmutable())->setTime(0, 0, 0); + } else { + $fromDeadline = null; + } + } +} diff --git a/tests/PHPStan/Analyser/nsrt/bug-14211.php b/tests/PHPStan/Analyser/nsrt/bug-14211.php new file mode 100644 index 00000000000..4bd902b825b --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-14211.php @@ -0,0 +1,28 @@ + $data */ +function doSomething(array $data): bool +{ + if (!isset($data['x'])) { + return false; + } + + $m = isset($data['y']); + + if ($m) { + assertType('true', $m); + } + assertType('bool', $m); + + if ($m) { + assertType('true', $m); + } + + return true; +} diff --git a/tests/PHPStan/Analyser/nsrt/bug-14411.php b/tests/PHPStan/Analyser/nsrt/bug-14411.php new file mode 100644 index 00000000000..753532ed59a --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-14411.php @@ -0,0 +1,34 @@ += 8.0 + +declare(strict_types = 1); + +namespace Bug14411; + +use function PHPStan\Testing\assertType; + +/** @phpstan-impure */ +function get_mixed(): mixed { + return random_int(0, 1) ? 'foo' : null; +} + +/** @phpstan-impure */ +function get_optional_int(): ?int { + return random_int(0, 1) ? 42 : null; +} + +function (): void { + $a = get_mixed(); + + if ($a !== null) { + $b = $a; + } + else { + $b = get_optional_int(); + } + if ($b !== null) { + assertType('mixed', $a); + if ($a === null) { + echo 'this is absolutely possible'; + } + } +};