Skip to content

Commit b07a1ab

Browse files
VincentLangletphpstan-bot
authored andcommitted
Fix phpstan/phpstan#14411: Incorrect type narrowing with dependent types
- In createConditionalExpressions(), type guards were created for variables whose branch types overlapped, allowing narrowing of one variable to incorrectly narrow a dependent variable from a different branch - Added a disjointness check: a variable is only used as a type guard when its "our" branch type and "their" branch type don't overlap - New regression test in tests/PHPStan/Analyser/nsrt/bug-14411.php
1 parent b70fb0f commit b07a1ab

File tree

2 files changed

+41
-0
lines changed

2 files changed

+41
-0
lines changed

src/Analyser/MutatingScope.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3580,6 +3580,13 @@ private function createConditionalExpressions(
35803580
continue;
35813581
}
35823582

3583+
if (
3584+
array_key_exists($exprString, $theirExpressionTypes)
3585+
&& !$holder->getType()->isSuperTypeOf($theirExpressionTypes[$exprString]->getType())->no()
3586+
) {
3587+
continue;
3588+
}
3589+
35833590
$typeGuards[$exprString] = $holder;
35843591
}
35853592

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php // lint >= 8.0
2+
3+
declare(strict_types = 1);
4+
5+
namespace Bug14411;
6+
7+
use function PHPStan\Testing\assertType;
8+
9+
/** @phpstan-impure */
10+
function get_mixed(): mixed {
11+
return random_int(0, 1) ? 'foo' : null;
12+
}
13+
14+
/** @phpstan-impure */
15+
function get_optional_int(): ?int {
16+
return random_int(0, 1) ? 42 : null;
17+
}
18+
19+
function (): void {
20+
$a = get_mixed();
21+
22+
if ($a !== null) {
23+
$b = $a;
24+
}
25+
else {
26+
$b = get_optional_int();
27+
}
28+
if ($b !== null) {
29+
assertType('mixed', $a);
30+
if ($a === null) {
31+
echo 'this is absolutely possible';
32+
}
33+
}
34+
};

0 commit comments

Comments
 (0)