diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 122340cc27b..1046029b244 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -3649,6 +3649,15 @@ private function createConditionalExpressions( ) { continue; } + if ( + !array_key_exists($exprString, $theirExpressionTypes) + && !$holder->getExpr() instanceof Variable + && array_key_exists($guardExprString, $theirExpressionTypes) + && $theirExpressionTypes[$guardExprString]->getCertainty()->yes() + && !$guardHolder->getType()->isSuperTypeOf($theirExpressionTypes[$guardExprString]->getType())->no() + ) { + continue; + } $conditionalExpression = new ConditionalExpressionHolder([$guardExprString => $guardHolder], $holder); $conditionalExpressions[$exprString][$conditionalExpression->getKey()] = $conditionalExpression; } diff --git a/tests/PHPStan/Analyser/nsrt/bug-14469.php b/tests/PHPStan/Analyser/nsrt/bug-14469.php new file mode 100644 index 00000000000..67bff59378f --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-14469.php @@ -0,0 +1,35 @@ +id === 10 ? 2 : null; + } elseif ($R['aa']) { + $aa = $R['aa']; + } + + if ($aa) { + assertType('mixed', $R['aa']); + } +} + +/** @param mixed $input */ +function variableEquivalent($input, bool $var1, object $user): void { + $aa = null; + $bb = $input; + + if ($var1) { + $aa = $user->id === 10 ? 2 : null; + } elseif ($bb) { + $aa = $bb; + } + + if ($aa) { + assertType('mixed', $bb); + } +} diff --git a/tests/PHPStan/Rules/Comparison/BooleanNotConstantConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/BooleanNotConstantConditionRuleTest.php index 3cf3f2a8bbc..ee1d1ff12fe 100644 --- a/tests/PHPStan/Rules/Comparison/BooleanNotConstantConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/BooleanNotConstantConditionRuleTest.php @@ -236,4 +236,10 @@ public function testBug6702(): void $this->analyse([__DIR__ . '/data/bug-6702.php'], []); } + public function testBug14469(): void + { + $this->treatPhpDocTypesAsCertain = true; + $this->analyse([__DIR__ . '/data/bug-14469.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Comparison/data/bug-14469.php b/tests/PHPStan/Rules/Comparison/data/bug-14469.php new file mode 100644 index 00000000000..66c6a98aa07 --- /dev/null +++ b/tests/PHPStan/Rules/Comparison/data/bug-14469.php @@ -0,0 +1,91 @@ +id === 10 ? 2 : null; + } elseif ($R['aa']) { + $aa = $R['aa']; + } + + if ($aa) { + if (!$R['aa']) { + return []; + } + } + return $R; +} + +/** Property fetch variant */ +function propertyFetch(object $obj, bool $var1, object $user): void { + $aa = null; + + if ($var1) { + $aa = $user->id === 10 ? 2 : null; + } elseif ($obj->prop) { + $aa = $obj->prop; + } + + if ($aa) { + if (!$obj->prop) { + return; + } + } +} + +/** Nested array fetch variant */ +function nestedArrayFetch(array $R, bool $var1, object $user): void { + $aa = null; + + if ($var1) { + $aa = $user->id === 10 ? 2 : null; + } elseif ($R['a']['b']) { + $aa = $R['a']['b']; + } + + if ($aa) { + if (!$R['a']['b']) { + return; + } + } +} + +/** Multiple elseif branches */ +function multipleElseif(array $R, bool $var1, bool $var2, object $user): void { + $aa = null; + + if ($var1) { + $aa = $user->id === 10 ? 2 : null; + } elseif ($var2) { + $aa = 5; + } elseif ($R['aa']) { + $aa = $R['aa']; + } + + if ($aa) { + if (!$R['aa']) { + return; + } + } +} + +/** @param mixed $input */ +function variableEquivalent(bool $var1, object $user, $input): void { + $aa = null; + $bb = $input; + + if ($var1) { + $aa = $user->id === 10 ? 2 : null; + } elseif ($bb) { + $aa = $bb; + } + + if ($aa) { + if (!$bb) { + return; + } + } +}