Fix #11730: array_filter with assert-if-true callable marks all keys optional#5097
Open
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
Open
Fix #11730: array_filter with assert-if-true callable marks all keys optional#5097phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
Conversation
- When array_filter callback has @phpstan-assert-if-true, check the falsey branch to determine if the callback can actually return false for the given input type - If filtering by falsey value makes the item/key type NeverType, the false branch is impossible, so the key should not be marked optional - New regression test in tests/PHPStan/Analyser/nsrt/bug-11730.php Closes phpstan/phpstan#11730
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When using
array_filterwith a callable annotated with@phpstan-assert-if-true, all keys in the resulting array were incorrectly marked as optional, even when the input elements already satisfied the asserted type. A callable with a conditional return type (@return ($value is Foo ? true : false)) correctly preserved keys as non-optional.Changes
processKeyAndItemType()insrc/Type/Php/ArrayFilterFunctionReturnTypeHelper.phpto check the falsey branch when the boolean result is not definitelytruefilterByFalseyValuemakes the item or key variable typeNeverType, the callback cannot return false for the given input type, so the key is not marked optionalRoot cause
The
processKeyAndItemType()method determined key optionality solely based on whether the callback's return type was definitelytrue($booleanResult->isTrue()->yes()). For@phpstan-assert-if-truecallbacks, the return type isbool(not conditionallytrue), so keys were always marked optional regardless of the input type.The fix adds a secondary check: when the return type isn't definitely
true, it evaluates the falsey branch. If filtering by the falsey value producesNeverTypefor the item or key variable, it means the false branch is impossible for this input type (e.g., passingFoothrough a callback that assertsFooon the true branch means the false branch would require!Foo, which isnever). In that case, the key is correctly kept as non-optional.Test
Added
tests/PHPStan/Analyser/nsrt/bug-11730.php— an NSRT test that verifiesarray_filterwith both a conditional return type callback and an@phpstan-assert-if-truecallback producearray{Foo, Foo}(non-optional keys) when filtering an array ofFooelements.Fixes phpstan/phpstan#11730