Skip to content

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
phpstan-bot:create-pull-request/patch-ybui14l
Open

Fix #7858: Redundant type casting drops next expression from condition and switches the context#5080
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-ybui14l

Conversation

@phpstan-bot
Copy link
Collaborator

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 $year to int<2022, max> after the if-throw, but instead reported int<48, 57>|int<256, max> (only the ctype_digit narrowing, ignoring the < 2022 comparison entirely).

Changes

  • Modified src/Analyser/TypeSpecifier.php in the Smaller/SmallerOrEqual handling section
  • Added logic to unwrap redundant cast expressions before creating type specifications
  • When a cast expression produces the same type as its inner expression (checked via Type::equals()), the inner expression is used for type narrowing instead of the cast expression
  • This ensures the narrowing is applied to the actual variable ($year) rather than the transient cast expression ((int) $year) which has no trackable identity in the scope

Root 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) $year was 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.php with two test functions:

  • One with (int) cast in the condition (the buggy case) - asserts int<2022, max>
  • One without the cast (already working) - asserts int<2022, max>

Fixes phpstan/phpstan#7858

- 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant