Fix #7858: Redundant type casting drops next expression from condition and switches the context#5080
Open
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
Open
Conversation
- Unwrap redundant cast expressions in Smaller/SmallerOrEqual type specifying so that narrowing propagates to the inner variable instead of the cast expr - When a cast produces the same type as its inner expression (e.g. (int) on an int variable), the narrowing is now applied to the original variable - New regression test in tests/PHPStan/Analyser/nsrt/bug-7858.php Closes phpstan/phpstan#7858
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 a redundant type cast like
(int)was used on a variable inside a comparison within a boolean OR condition, PHPStan dropped the type narrowing from the comparison and reported the wrong type. For example,if (!ctype_digit($year) || (int) $year < 2022)should narrow$yeartoint<2022, max>after the if-throw, but instead reportedint<48, 57>|int<256, max>(only the ctype_digit narrowing, ignoring the< 2022comparison entirely).Changes
src/Analyser/TypeSpecifier.phpin theSmaller/SmallerOrEqualhandling sectionType::equals()), the inner expression is used for type narrowing instead of the cast expression$year) rather than the transient cast expression ((int) $year) which has no trackable identity in the scopeRoot cause
The
TypeSpecifier::specifyTypesInCondition()method creates type specifications keyed by expression string. When the left side of<was(int) $year, the narrowing was created for the expression string(int) $year. However, the scope only tracks the variable$year, so the narrowing for(int) $yearwas never matched and applied. When the cast is redundant (the inner expression already has the target type), the cast should be unwrapped so the narrowing targets the actual variable.Test
Added
tests/PHPStan/Analyser/nsrt/bug-7858.phpwith two test functions:(int)cast in the condition (the buggy case) - assertsint<2022, max>int<2022, max>Fixes phpstan/phpstan#7858