Skip to content

Fix #12244: $this(Type~Subtracted) does not work on conditional return type as Type~Subtracted#5104

Open
phpstan-bot wants to merge 2 commits intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-v4r9h71
Open

Fix #12244: $this(Type~Subtracted) does not work on conditional return type as Type~Subtracted#5104
phpstan-bot wants to merge 2 commits intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-v4r9h71

Conversation

@phpstan-bot
Copy link
Collaborator

Summary

When a method has a conditional return type referencing $this (e.g., @return ($this is self::A ? int : null)) and $this has been narrowed via type subtraction (e.g., inside if ($this !== self::A)), the conditional return type was not properly resolved. It returned int|null instead of null, even though the same narrowing worked correctly for non-$this variables.

Changes

  • Modified StaticType::transformStaticType() in src/Type/StaticType.php to propagate the calling type's subtracted type when transforming StaticType instances in return types
  • Added regression test tests/PHPStan/Analyser/nsrt/bug-12244.php

Root cause

When PHPStan resolves method return types, it transforms StaticType/ThisType instances in the return type to reflect the actual calling type. For regular object types ($x: X~X::A), CalledOnTypeUnresolvedMethodPrototypeReflection::transformStaticType replaces StaticType with the full caller type including its subtracted type. However, for $this types ($this(X~X::A)), StaticType::transformStaticType only changed the base class of StaticType instances without propagating the subtracted type from the calling $this. This meant the conditional ($this is self::A ? int : null) could not determine that $this was definitely not self::A.

The fix adds subtracted type propagation in StaticType::transformStaticType, ensuring consistency with how CalledOnType handles the same scenario.

Test

Added tests/PHPStan/Analyser/nsrt/bug-12244.php which tests:

  • $this->get() inside an instance method after narrowing $this via if ($this !== self::A) correctly returns null
  • $x->get() inside a static method after narrowing $x via if ($x !== self::A) correctly returns null (was already working)

Fixes phpstan/phpstan#12244

- When a method has a conditional return type like `@return ($this is self::A ? int : null)`,
  and `$this` has a subtracted type (e.g. `$this(X~X::A)` from narrowing), the conditional
  was not properly resolved because the subtracted type was not propagated
- The root cause was in `StaticType::transformStaticType` which transforms `StaticType`
  instances in return types but did not propagate the calling type's subtracted type
- Added subtracted type propagation in `StaticType::transformStaticType` to match the
  behavior of `CalledOnTypeUnresolvedMethodPrototypeReflection::transformStaticType`
- New regression test in tests/PHPStan/Analyser/nsrt/bug-12244.php

Closes phpstan/phpstan#12244
@VincentLanglet VincentLanglet force-pushed the create-pull-request/patch-v4r9h71 branch from fa23f75 to f871587 Compare February 28, 2026 16:03
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