diff --git a/tests/PHPStan/Analyser/nsrt/bug-14213.php b/tests/PHPStan/Analyser/nsrt/bug-14213.php new file mode 100644 index 0000000000..50dd715229 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-14213.php @@ -0,0 +1,102 @@ +|null', $x); + } + + public static function coalesce_int_ranges(): void + { + $x0 = $x1 = $x2 = null; + + if (rand(0, 1)) { + $x0 = rand(0, 1); + } + if (rand(0, 1)) { + $x1 = rand(2, 3); + } + if (rand(0, 1)) { + $x2 = rand(4, 5); + } + + $x = ( + $x0 ?? + $x1 ?? + $x2 + ); + + assertType('int<0, 5>|null', $x); + } + + public static function coalesce_int_range_after_maybe_defined(): void + { + $x0 = $x1 = $x2 = null; + + if (rand(0, 1)) { + $maybeDefined = 10; + } + if (rand(0, 1)) { + $x0 = rand(0, 1); + } + if (rand(0, 1)) { + $x1 = rand(2, 3); + } + if (rand(0, 1)) { + $x2 = rand(4, 5); + } + + $x = ( + $maybeDefined ?? + $x0 ?? + $x1 ?? + $x2 + ); + + assertType('10|int<0, 5>|null', $x); + } + + public static function coalesce_int_range_with_last_non_nullable(): void + { + $x0 = $x1 = null; + $x2 = 20; + + if (rand(0, 1)) { + $x0 = rand(0, 1); + } + if (rand(0, 1)) { + $x1 = rand(2, 3); + } + if (rand(0, 1)) { + $x2 = rand(4, 5); + } + + $x = ( + $x0 ?? + $x1 ?? + $x2 // cannot be null + ); + + assertType('20|int<0, 5>', $x); + } +} diff --git a/tests/PHPStan/Rules/Variables/NullCoalesceRuleTest.php b/tests/PHPStan/Rules/Variables/NullCoalesceRuleTest.php index de2e966abb..56b902212a 100644 --- a/tests/PHPStan/Rules/Variables/NullCoalesceRuleTest.php +++ b/tests/PHPStan/Rules/Variables/NullCoalesceRuleTest.php @@ -352,4 +352,14 @@ public function testPr4372(): void $this->analyse([__DIR__ . '/data/pr-4372-null-coalesce.php'], []); } + public function testBug14213(): void + { + $this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-14213.php'], [ + [ + 'Variable $x1 on left side of ?? always exists and is always null.', + 22, + ], + ]); + } + }