Skip to content

Commit 0ec5f54

Browse files
phpstan-botclaude
andcommitted
Relax subtype matching to work with non-finite union guard types
Replace the `count(getFiniteTypes()) > 1` restriction with a `!$guardType instanceof MixedType` check. This allows conditional expressions with non-finite union guards (e.g. int|string) to match when the specified type is a strict subtype, while still preventing incorrect matches against mixed-based types that would cause *NEVER* type collapses. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 5796511 commit 0ec5f54

File tree

3 files changed

+31
-2
lines changed

3 files changed

+31
-2
lines changed

src/Analyser/MutatingScope.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3226,12 +3226,13 @@ public function filterBySpecifiedTypes(SpecifiedTypes $specifiedTypes): self
32263226
if ($specifiedHolder->equals($conditionalTypeHolder)) {
32273227
continue;
32283228
}
3229+
$guardType = $conditionalTypeHolder->getType();
32293230
if (
32303231
$conditionalExpression->getTypeHolder()->getCertainty()->yes()
32313232
&& $specifiedHolder->getCertainty()->yes()
32323233
&& $conditionalTypeHolder->getCertainty()->yes()
3233-
&& count($conditionalTypeHolder->getType()->getFiniteTypes()) > 1
3234-
&& $conditionalTypeHolder->getType()->isSuperTypeOf($specifiedHolder->getType())->yes()
3234+
&& !$guardType instanceof MixedType
3235+
&& $guardType->isSuperTypeOf($specifiedHolder->getType())->yes()
32353236
) {
32363237
$subtypeMatch = true;
32373238
continue;

tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,6 +1485,15 @@ public function testBug12597(): void
14851485
$this->analyse([__DIR__ . '/data/bug-12597.php'], []);
14861486
}
14871487

1488+
public function testBug12597NonFinite(): void
1489+
{
1490+
$this->cliArgumentsVariablesRegistered = true;
1491+
$this->polluteScopeWithLoopInitialAssignments = false;
1492+
$this->checkMaybeUndefinedVariables = true;
1493+
$this->polluteScopeWithAlwaysIterableForeach = true;
1494+
$this->analyse([__DIR__ . '/data/bug-12597-non-finite.php'], []);
1495+
}
1496+
14881497
public function testBug14117(): void
14891498
{
14901499
$this->cliArgumentsVariablesRegistered = true;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug12597NonFinite;
4+
5+
class HelloWorld
6+
{
7+
public function test(mixed $type): void
8+
{
9+
if (is_int($type) || is_string($type)) {
10+
$message = 'Hello!';
11+
}
12+
13+
if (is_int($type)) {
14+
$this->message($message);
15+
}
16+
}
17+
18+
public function message(string $message): void {}
19+
}

0 commit comments

Comments
 (0)