Skip to content

Fix #13023: function.alreadyNarrowedType and function.impossibleType after updates to 2.1.15#5084

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

Fix #13023: function.alreadyNarrowedType and function.impossibleType after updates to 2.1.15#5084
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-vgte5je

Conversation

@phpstan-bot
Copy link
Collaborator

Summary

When a trait method contains is_a($this, SomeClass::class) and the trait is used by multiple classes, PHPStan falsely reports:

  • function.alreadyNarrowedType ("will always evaluate to true") when analyzing the trait in the context of SomeClass
  • function.impossibleType ("will always evaluate to false") when analyzing the trait in the context of SomeClass2

Both are false positives because the trait code is shared across classes and the check is valid polymorphic behavior.

Changes

  • Modified src/Rules/Comparison/ImpossibleCheckTypeHelper.php:
    • In findSpecifiedType(), added checks in both the sureTypes and sureNotTypes loops to treat class-specific type checks on $this as uncertain (TrinaryLogic::createMaybe()) when the scope is inside a trait
    • Added isThis() private static helper to detect $this variable expressions
  • Added regression test tests/PHPStan/Rules/Comparison/data/bug-13023.php
  • Added test method testBug13023() in ImpossibleCheckTypeFunctionCallRuleTest.php

Root cause

PHPStan analyzes trait methods once per class that uses the trait, each time with $this typed as that specific class. The ImpossibleCheckTypeHelper::findSpecifiedType() method compares the narrowed type (e.g., ObjectType('SomeClass')) against the argument type (e.g., $this(SomeClass) or $this(SomeClass2)), producing a definitive yes/no result for each class context. However, since trait code is shared, these definitive results are false positives.

The fix detects when we're in a trait context and the sure type expression is $this with a class-specific result type (i.e., getObjectClassNames() !== []). In that case, the result is treated as uncertain, preventing the false positive. Non-class-specific checks like is_int($this) or is_object($this) are not affected, as they produce correct results regardless of which class uses the trait.

Test

Added tests/PHPStan/Rules/Comparison/data/bug-13023.php with a trait MyTrait used by SomeClass and SomeClass2, where the trait method calls is_a($this, SomeClass::class). The test expects no errors (empty array), confirming the false positives are suppressed.

Fixes phpstan/phpstan#13023

- In ImpossibleCheckTypeHelper::findSpecifiedType(), treat class-specific type
  checks on $this as uncertain when inside a trait, since $this is polymorphic
  across the different classes that use the trait
- Added isThis() helper method for detecting $this expression references
- New regression test in tests/PHPStan/Rules/Comparison/data/bug-13023.php

Closes phpstan/phpstan#13023
$argumentType = $scope->getType($assignedInCallVar->expr);
}

if ($isInTrait && self::isThis($sureType[0]) && $resultType->getObjectClassNames() !== []) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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