Skip to content

Commit 2ee73af

Browse files
phpstan-botondrejmirtesclaude
authored
Fix: false positive “Match expression does not handle remaining value: int<...>” for match (count(...)) { ...}
Co-authored-by: ondrejmirtes <104888+ondrejmirtes@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 98a3159 commit 2ee73af

File tree

3 files changed

+38
-4
lines changed

3 files changed

+38
-4
lines changed

src/Analyser/TypeSpecifier.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2568,7 +2568,7 @@ private function resolveNormalizedIdentical(Expr\BinaryOp\Identical $expr, Scope
25682568
$argType = $scope->getType($unwrappedLeftExpr->getArgs()[0]->value);
25692569
$isZero = (new ConstantIntegerType(0))->isSuperTypeOf($rightType);
25702570
if ($isZero->yes()) {
2571-
$funcTypes = $this->create($unwrappedLeftExpr, $rightType, $context, $scope)->setRootExpr($expr);
2571+
$funcTypes = $this->create($leftExpr, $rightType, $context, $scope)->setRootExpr($expr);
25722572

25732573
if ($context->truthy() && !$argType->isArray()->yes()) {
25742574
$newArgType = new UnionType([
@@ -2586,11 +2586,15 @@ private function resolveNormalizedIdentical(Expr\BinaryOp\Identical $expr, Scope
25862586

25872587
$specifiedTypes = $this->specifyTypesForCountFuncCall($unwrappedLeftExpr, $argType, $rightType, $context, $scope, $expr);
25882588
if ($specifiedTypes !== null) {
2589+
if ($leftExpr !== $unwrappedLeftExpr) {
2590+
$funcTypes = $this->create($leftExpr, $rightType, $context, $scope)->setRootExpr($expr);
2591+
return $specifiedTypes->unionWith($funcTypes);
2592+
}
25892593
return $specifiedTypes;
25902594
}
25912595

25922596
if ($context->truthy() && $argType->isArray()->yes()) {
2593-
$funcTypes = $this->create($unwrappedLeftExpr, $rightType, $context, $scope)->setRootExpr($expr);
2597+
$funcTypes = $this->create($leftExpr, $rightType, $context, $scope)->setRootExpr($expr);
25942598
if (IntegerRangeType::fromInterval(1, null)->isSuperTypeOf($rightType)->yes()) {
25952599
return $funcTypes->unionWith(
25962600
$this->create($unwrappedLeftExpr->getArgs()[0]->value, new NonEmptyArrayType(), $context, $scope)->setRootExpr($expr),
@@ -2616,7 +2620,7 @@ private function resolveNormalizedIdentical(Expr\BinaryOp\Identical $expr, Scope
26162620

26172621
$isZero = (new ConstantIntegerType(0))->isSuperTypeOf($rightType);
26182622
if ($isZero->yes()) {
2619-
$funcTypes = $this->create($unwrappedLeftExpr, $rightType, $context, $scope)->setRootExpr($expr);
2623+
$funcTypes = $this->create($leftExpr, $rightType, $context, $scope)->setRootExpr($expr);
26202624
return $funcTypes->unionWith(
26212625
$this->create($unwrappedLeftExpr->getArgs()[0]->value, new ConstantStringType(''), $context, $scope)->setRootExpr($expr),
26222626
);
@@ -2625,7 +2629,7 @@ private function resolveNormalizedIdentical(Expr\BinaryOp\Identical $expr, Scope
26252629
if ($context->truthy() && IntegerRangeType::fromInterval(1, null)->isSuperTypeOf($rightType)->yes()) {
26262630
$argType = $scope->getType($unwrappedLeftExpr->getArgs()[0]->value);
26272631
if ($argType->isString()->yes()) {
2628-
$funcTypes = $this->create($unwrappedLeftExpr, $rightType, $context, $scope)->setRootExpr($expr);
2632+
$funcTypes = $this->create($leftExpr, $rightType, $context, $scope)->setRootExpr($expr);
26292633

26302634
$accessory = new AccessoryNonEmptyStringType();
26312635
if (IntegerRangeType::fromInterval(2, null)->isSuperTypeOf($rightType)->yes()) {

tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,12 @@ public function testBug13029(): void
453453
$this->analyse([__DIR__ . '/data/bug-13029.php'], []);
454454
}
455455

456+
#[RequiresPhp('>= 8.0')]
457+
public function testBug12790(): void
458+
{
459+
$this->analyse([__DIR__ . '/data/bug-12790.php'], []);
460+
}
461+
456462
#[RequiresPhp('>= 8.0')]
457463
public function testBug11310(): void
458464
{
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php // lint >= 8.0
2+
3+
declare(strict_types = 1);
4+
5+
namespace Bug12790;
6+
7+
$r = [];
8+
$r[] = 'a';
9+
if (rand(0, 1)) {
10+
$r[] = 'b';
11+
}
12+
13+
echo match (count($r)) {
14+
1 => 'one',
15+
2 => 'two',
16+
};
17+
18+
/** @param 'a'|'ab' $s */
19+
function matchStrlen(string $s): string {
20+
return match (strlen($s)) {
21+
1 => 'one',
22+
2 => 'two',
23+
};
24+
}

0 commit comments

Comments
 (0)