diff --git a/src/Analyser/TypeSpecifier.php b/src/Analyser/TypeSpecifier.php index e5acf1739e..9b1e118976 100644 --- a/src/Analyser/TypeSpecifier.php +++ b/src/Analyser/TypeSpecifier.php @@ -731,6 +731,16 @@ public function specifyTypesInCondition( } return $types; + } elseif ( + $expr instanceof Expr\BinaryOp\Coalesce + && $context->true() + && ((new ConstantBooleanType(false))->isSuperTypeOf($scope->getType($expr->right))->yes()) + ) { + return $this->create( + $expr->left, + new NullType(), + TypeSpecifierContext::createFalse() + ); } elseif ( $expr instanceof Expr\Empty_ && $context->truthy() && (new ArrayType(new MixedType(), new MixedType()))->isSuperTypeOf($scope->getType($expr->expr))->yes() diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index 6fc9d59fd4..634e6ebb0e 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -5755,6 +5755,11 @@ public function dataTernarySpecifiedTypes(): array return $this->gatherAssertTypes(__DIR__ . '/data/ternary-specified-types.php'); } + public function dataBug560(): array + { + return $this->gatherAssertTypes(__DIR__ . '/data/bug-560.php'); + } + /** * @dataProvider dataArrayFunctions * @param string $description @@ -11389,6 +11394,7 @@ private function gatherAssertTypes(string $file): array * @dataProvider dataBug2977 * @dataProvider dataBug3190 * @dataProvider dataTernarySpecifiedTypes + * @dataProvider dataBug560 * @param string $assertType * @param string $file * @param mixed ...$args diff --git a/tests/PHPStan/Analyser/data/bug-560.php b/tests/PHPStan/Analyser/data/bug-560.php new file mode 100644 index 0000000000..a3a4ac91a6 --- /dev/null +++ b/tests/PHPStan/Analyser/data/bug-560.php @@ -0,0 +1,22 @@ +