Skip to content

Commit

Permalink
Specify types on match() condition correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
rvanvelzen authored and ondrejmirtes committed May 8, 2024
1 parent e55a83f commit 149a1e7
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 4 deletions.
13 changes: 9 additions & 4 deletions src/Analyser/TypeSpecifier.php
Expand Up @@ -1991,11 +1991,16 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty
$exprNode = $expressions[0];
$constantType = $expressions[1];

$specifiedType = $this->specifyTypesForConstantBinaryExpression($exprNode, $constantType, $context, $scope, $rootExpr);
$unwrappedExprNode = $exprNode;
if ($exprNode instanceof AlwaysRememberedExpr) {
$unwrappedExprNode = $exprNode->getExpr();
}

$specifiedType = $this->specifyTypesForConstantBinaryExpression($unwrappedExprNode, $constantType, $context, $scope, $rootExpr);
if ($specifiedType !== null) {
if ($exprNode instanceof AlwaysRememberedExpr) {
$specifiedType->unionWith(
$this->create($exprNode->getExpr(), $constantType, $context, false, $scope, $rootExpr),
if ($exprNode !== $unwrappedExprNode) {
$specifiedType = $specifiedType->unionWith(
$this->create($exprNode, $constantType, $context, false, $scope, $rootExpr),
);
}
return $specifiedType;
Expand Down
Expand Up @@ -1669,4 +1669,13 @@ public function testBug10297(): void
$this->analyse([__DIR__ . '/data/bug-10297.php'], []);
}

public function testBug10974(): void
{
if (PHP_VERSION_ID < 80000) {
$this->markTestSkipped('Test requires PHP 8.0.');
}

$this->analyse([__DIR__ . '/data/bug-10974.php'], []);
}

}
27 changes: 27 additions & 0 deletions tests/PHPStan/Rules/Functions/data/bug-10974.php
@@ -0,0 +1,27 @@
<?php declare(strict_types = 1); // lint >= 8.0

namespace Bug10974;

function non(): void {}
function single(string $str): void {}
/** @param non-empty-array<string> $strs */
function multiple(array $strs): void {}

/** @param array<string> $arr */
function test(array $arr): void
{
match (count($arr))
{
0 => non(),
1 => single(reset($arr)),
default => multiple($arr)
};

if (empty($arr)) {
non();
} elseif (count($arr) === 1) {
single(reset($arr));
} else {
multiple($arr);
}
}
12 changes: 12 additions & 0 deletions tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php
Expand Up @@ -937,4 +937,16 @@ public function testBug8629(): void
$this->analyse([__DIR__ . '/data/bug-8629.php'], []);
}

public function testBug9694(): void
{
if (PHP_VERSION_ID < 80000) {
$this->markTestSkipped('Test requires PHP 8.0.');
}

$this->checkThisOnly = false;
$this->checkUnionTypes = true;
$this->checkDynamicProperties = true;
$this->analyse([__DIR__ . '/data/bug-9694.php'], []);
}

}
20 changes: 20 additions & 0 deletions tests/PHPStan/Rules/Properties/data/bug-9694.php
@@ -0,0 +1,20 @@
<?php declare(strict_types = 1); // lint >= 8.0

class TotpEnrollment
{
public bool $confirmed;
}

class User
{
public ?TotpEnrollment $totpEnrollment;
}

function () {
$user = new User();

return match ($user->totpEnrollment === null) {
true => false,
false => $user->totpEnrollment->confirmed,
};
};

0 comments on commit 149a1e7

Please sign in to comment.