Open adamkoppede opened 7 months ago
In Snippet:
<?php /** * @var list<int> $arr */ $arr = []; $hasNumberOne = false; \usort( $arr, static function (mixed $left, mixed $right) use (&$hasNumberOne): int { if ($left === 1 || $right === 1) { $hasNumberOne = true; return 0; } return $left <=> $right; } ); if ($hasNumberOne) { echo "hasNumberOne"; }
I expect $hasNumberOne to be of type bool after the call to \usort. Currently an TypeDoesNotContainType error is thrown for the last if statement: https://psalm.dev/r/a41c3c69f8.
$hasNumberOne
bool
\usort
The issue can be worked around by adding an explicit type annotation with type bool to the first assignment of $hasNumberOne: https://psalm.dev/r/f23829106d
When I tried to look into the issue myself with an extended version of the snippet (https://psalm.dev/r/30c782d34a / github commit for test):
<?php /** * @var list<int> $arr */ $arr = [0, 1, 2]; $hasSomeNumber = false; $hasNumberOne = false; \usort( $arr, static function ($left, $right) use (&$hasSomeNumber, &$hasNumberOne): int { $hasSomeNumber = true; if ($left === 1 || $right === 1) { $hasNumberOne = true; return 0; } return $left <=> $right; } ); if ($hasSomeNumber) { // has expected type `bool` echo "hasSomeNumber"; } if ($hasNumberOne) { // has unexpected type `false` echo "hasNumberOne"; }
I found that the change from TFalse to TTrue inside the conditional is correctly determined in the local variable $if_context in \Psalm\Internal\Analyzer\Statements\Block\IfElse\IfAnalyzer::analyze. However, it isn't carried up into $ref_context in \Psalm\Internal\Analyzer\FunctionLikeAnalyzer::analyze. There in $ref_context, $hasSomeNumber is of expected type TBool while $hasNumberOne remains of unexpected type TFalse.
TFalse
TTrue
$if_context
\Psalm\Internal\Analyzer\Statements\Block\IfElse\IfAnalyzer::analyze
$ref_context
\Psalm\Internal\Analyzer\FunctionLikeAnalyzer::analyze
$hasSomeNumber
TBool
I found these snippets:
In Snippet:
I expect
$hasNumberOne
to be of typebool
after the call to\usort
. Currently an TypeDoesNotContainType error is thrown for the last if statement: https://psalm.dev/r/a41c3c69f8.The issue can be worked around by adding an explicit type annotation with type
bool
to the first assignment of$hasNumberOne
: https://psalm.dev/r/f23829106dWhen I tried to look into the issue myself with an extended version of the snippet (https://psalm.dev/r/30c782d34a / github commit for test):
I found that the change from
TFalse
toTTrue
inside the conditional is correctly determined in the local variable$if_context
in\Psalm\Internal\Analyzer\Statements\Block\IfElse\IfAnalyzer::analyze
. However, it isn't carried up into$ref_context
in\Psalm\Internal\Analyzer\FunctionLikeAnalyzer::analyze
. There in$ref_context
,$hasSomeNumber
is of expected typeTBool
while$hasNumberOne
remains of unexpected typeTFalse
.