Skip to content

Fix phpstan/phpstan#6705: Solve in_array() once and for all#5380

Open
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-ueg44zb
Open

Fix phpstan/phpstan#6705: Solve in_array() once and for all#5380
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-ueg44zb

Conversation

@phpstan-bot
Copy link
Copy Markdown
Collaborator

Summary

  • Remove the ~100-line special-case in_array handling from ImpossibleCheckTypeHelper (lines 98-198) as requested in Solve in_array() once and for all phpstan#6705
  • Handle all in_array impossibility detection entirely within InArrayFunctionTypeSpecifyingExtension using the rootExpr mechanism
  • The extension now always sets a rootExpr for strict in_array calls, using ConstFetch('true') / ConstFetch('false') / ConstFetch('__PHPSTAN_FAUX_CONSTANT') to signal always-true, always-false, or indeterminate results respectively
  • This also fixes detection for previously-undetected cases with explicit strict parameter on enum types

Changes

src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php

  • Added determineRootExpr() method that checks type compatibility and guaranteed containment
  • Added isGuaranteedToContainNeedle() method for always-true detection (handles both ConstantArrayType with non-optional keys and generic arrays with single finite value type)
  • Added computeNeedleNarrowingType() method for false-context needle type narrowing
  • Added rootExpr to the non-strict path to prevent false positives
  • Replaced instanceof ConstantArrayType with getConstantArrays() per PHPStan conventions

src/Rules/Comparison/ImpossibleCheckTypeHelper.php

  • Removed the entire in_array special-case block (~100 lines)
  • Removed unused imports (ConstantArrayType, NeverType)

Test changes

  • Added regression test tests/PHPStan/Rules/Comparison/data/bug-6705.php
  • Updated enum test expectations for newly-detected cases (lines 165/168/171/174 in loose-comparison-against-enums.php)
  • Updated binary.php assertion: in_array('foo', ['foo', 'bar']) now correctly inferred as true instead of bool
  • Updated baseline to remove obsolete instanceof ConstantArrayType ignores

Test plan

  • make tests - all 11722 tests pass
  • make phpstan - no errors
  • make cs-fix - no violations
  • make name-collision - pre-existing failure (unrelated pipe-operator syntax)

…to InArrayFunctionTypeSpecifyingExtension

Remove the ~100-line special-case in_array handling from ImpossibleCheckTypeHelper
and handle all impossibility detection entirely within the type-specifying extension
using the rootExpr mechanism.

The extension now returns:
- ConstFetch('true') rootExpr when in_array is guaranteed to always return true
- ConstFetch('false') rootExpr when types are incompatible (always false)
- ConstFetch('__PHPSTAN_FAUX_CONSTANT') rootExpr for indeterminate cases

This approach bypasses the sureTypes-based detection in ImpossibleCheckTypeHelper,
which suffered from scope leakage issues (e.g., ClassConstFetch expressions for
enum cases being marked as "specified" by prior in_array calls in the same scope).

Fixes phpstan/phpstan#6705

Also fixes detection of previously-undetected cases:
- in_array(Enum::A, non-empty-array<Enum::A>, false/true) now correctly reports
  "always true" when enum type guarantees a match
- in_array(Enum::B, array<Enum::A>, false/true) now correctly reports
  "always false" when enum types are incompatible
- in_array('foo', ['foo', 'bar']) without strict param is now correctly narrowed
  to return type `true` (string-to-string comparison is equivalent to strict)
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.

2 participants