-
Notifications
You must be signed in to change notification settings - Fork 578
Fix phpstan/phpstan#13566: False positive staticMethod.impossibleType #5121
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
staabm
merged 22 commits into
phpstan:2.1.x
from
phpstan-bot:create-pull-request/patch-82dxt57
Mar 3, 2026
Merged
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
e7f4f35
Fix phpstan/phpstan#13566: False positive staticMethod.impossibleType…
staabm f5f9776
more tests
staabm f84c317
fix
staabm a3a7754
another test
staabm 24c8441
Discard changes to src/Rules/Comparison/ImpossibleCheckTypeHelper.php
staabm 6e2f4cf
test instance-method calls and function calls
staabm 0280266
fix
staabm 258f9fe
revert to ai fix
staabm 583e650
Update TypeSpecifier.php
staabm fa2a509
Update ImpossibleCheckTypeHelper.php
staabm dd2ef33
Update TypeSpecifier.php
staabm 8b79a75
Update bug-13566.php
staabm 0845eb4
added regression test
staabm 77c2b68
Discard changes to src/Rules/Comparison/ImpossibleCheckTypeHelper.php
staabm 3c7ee01
simplify
staabm 478f22a
test string scalar
staabm e86a0d6
test union
staabm 1028e85
Revert "test union"
staabm bf87648
fix union types
staabm ae982ee
try suggestions
staabm 59a1dfc
more tests
staabm d1f2dcb
fix
staabm File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| <?php declare(strict_types=1); | ||
|
|
||
| namespace Bug10337; | ||
|
|
||
| use function PHPStan\Testing\assertType; | ||
|
|
||
| class App | ||
| { | ||
| /** | ||
| * @return ($calledFromShutdownHandler is true ? void : never) | ||
| */ | ||
| public function callExit(bool $calledFromShutdownHandler = false): void | ||
| { | ||
| // run before shutdown code here | ||
|
|
||
| if (!$calledFromShutdownHandler) { | ||
| exit; | ||
| } | ||
| } | ||
|
|
||
| public function testOnlyVoid(): void | ||
| { | ||
| (new App())->callExit(true); | ||
| } | ||
|
|
||
| /** | ||
| * @return never | ||
| */ | ||
| public function testVoidAndNever(): void | ||
| { | ||
| $app = new App(); | ||
| assertType('null', $app->callExit(true)); | ||
| assertType('never', $app->callExit(false)); | ||
| } | ||
|
|
||
| /** | ||
| * @return never | ||
| */ | ||
| public function testVoidAndNever2(): void | ||
| { | ||
| $app = new class() extends App { | ||
| }; | ||
| assertType('null', $app->callExit(true)); | ||
| assertType('never', $app->callExit(false)); | ||
| } | ||
|
|
||
| /** | ||
| * @return never | ||
| */ | ||
| public function testVoidAndNever3(): void | ||
| { | ||
| $app = new class() extends App { | ||
| #[\Override] | ||
| public function callExit(bool $calledFromShutdownHandler = false): void | ||
| { | ||
| parent::callExit($calledFromShutdownHandler); | ||
| } | ||
| }; | ||
| assertType('null', $app->callExit(true)); | ||
| assertType('never', $app->callExit(false)); | ||
| } | ||
| } |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,212 @@ | ||
| <?php // lint >= 8.0 | ||
|
|
||
| declare(strict_types = 1); | ||
|
|
||
| namespace Bug13566; | ||
|
|
||
| use LogicException; | ||
|
|
||
| class ReturnViaBool | ||
| { | ||
| /** @return ($exit is true ? never : void) */ | ||
| public static function notFound(bool $exit = true): void | ||
| { | ||
| header('HTTP/1.1 404 Not Found', true, 404); | ||
|
|
||
| if ($exit) { | ||
| echo '404 Not Found'; | ||
| exit; | ||
| } | ||
| } | ||
|
|
||
| public function test(): void | ||
| { | ||
| // send 404 header without exiting | ||
| self::notFound(false); | ||
| } | ||
| } | ||
|
|
||
| class ReturnViaInt | ||
| { | ||
| /** @return ($exit is 1 ? never : void) */ | ||
| public static function notFound(int $exit = 1): void | ||
| { | ||
| header('HTTP/1.1 404 Not Found', true, 404); | ||
|
|
||
| if ($exit == 1) { | ||
| echo '404 Not Found'; | ||
| exit; | ||
| } | ||
| } | ||
|
|
||
| public function test(): void | ||
| { | ||
| // send 404 header | ||
| self::notFound(0); | ||
| } | ||
| } | ||
|
|
||
| class ReturnViaString | ||
| { | ||
| /** @return ($exit is '1' ? never : void) */ | ||
| public static function notFound(string $exit = '1'): void | ||
| { | ||
| header('HTTP/1.1 404 Not Found', true, 404); | ||
|
|
||
| if ($exit == '1') { | ||
| echo '404 Not Found'; | ||
| exit; | ||
| } | ||
| } | ||
|
|
||
| public function test(): void | ||
| { | ||
| // send 404 header | ||
| self::notFound('0'); | ||
| } | ||
| } | ||
|
|
||
| class ReturnViaIntNonNative | ||
| { | ||
| /** @return ($exit is 1 ? never : void) */ | ||
| public static function notFound(int $exit = 1) | ||
| { | ||
| header('HTTP/1.1 404 Not Found', true, 404); | ||
|
|
||
| if ($exit == 1) { | ||
| echo '404 Not Found'; | ||
| exit; | ||
| } | ||
| } | ||
|
|
||
| public function test(): void | ||
| { | ||
| // send 404 header | ||
| self::notFound(0); | ||
| } | ||
| } | ||
|
|
||
| class ReturnsMaybeNever | ||
| { | ||
| /** @return ($exit is true ? never : 1) */ | ||
| public static function notFound(bool $exit = true) | ||
| { | ||
| header('HTTP/1.1 404 Not Found', true, 404); | ||
|
|
||
| if ($exit) { | ||
| echo '404 Not Found'; | ||
| exit; | ||
| } | ||
| return 1; | ||
| } | ||
|
|
||
| public function test(): void | ||
| { | ||
| // send 404 header | ||
| self::notFound(false); | ||
|
|
||
| } | ||
| } | ||
|
|
||
| class ReturnsMaybeVoid | ||
| { | ||
| /** @return ($exit is true ? void : 1) */ | ||
| public static function notFound(bool $exit = true) | ||
| { | ||
| header('HTTP/1.1 404 Not Found', true, 404); | ||
|
|
||
| if ($exit) { | ||
| echo '404 Not Found'; | ||
| return; | ||
| } | ||
| return 1; | ||
| } | ||
|
|
||
| public function test(): void | ||
| { | ||
| // send 404 header | ||
| self::notFound(false); | ||
|
|
||
| } | ||
| } | ||
|
|
||
|
|
||
|
|
||
| class ReturnsWithInstanceMethod | ||
| { | ||
| /** @return ($exit is true ? never-return : void) */ | ||
| public function notFound(bool $exit = true): void | ||
| { | ||
| header('HTTP/1.1 404 Not Found', true, 404); | ||
|
|
||
| if ($exit) { | ||
| echo '404 Not Found'; | ||
| exit; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| public function test(): void | ||
| { | ||
| // send 404 header | ||
| $this->notFound(false); | ||
|
|
||
| } | ||
| } | ||
|
|
||
| /** @return ($exit is true ? never-return : void) */ | ||
| function notFound(bool $exit = true): void | ||
| { | ||
| header('HTTP/1.1 404 Not Found', true, 404); | ||
|
|
||
| if ($exit) { | ||
| echo '404 Not Found'; | ||
| exit; | ||
| } | ||
| } | ||
|
|
||
| function test(): void | ||
| { | ||
| // send 404 header | ||
| notFound(false); | ||
| } | ||
|
|
||
|
|
||
| class ReturnViaUnion | ||
| { | ||
| /** | ||
| * @return ($exit is int ? void : never) | ||
| */ | ||
| public static function notFound(int|string $exit = 'hello world'): void | ||
| { | ||
| header('HTTP/1.1 404 Not Found', true, 404); | ||
|
|
||
| if (!is_int($exit)) { | ||
| echo '404 Not Found'; | ||
| exit; | ||
| } | ||
| } | ||
|
|
||
| public function test(): void | ||
| { | ||
| // send 404 header | ||
| self::notFound(0); | ||
| } | ||
| } | ||
|
|
||
|
|
||
| $x = 123; | ||
| if (is_numeric($x)) { | ||
| } | ||
|
|
||
| function doFoo($mixed) { | ||
| assertIsInt($mixed); | ||
| assertIsInt($mixed); | ||
| } | ||
|
|
||
| /** @phpstan-assert int $i */ | ||
| function assertIsInt($i):void { | ||
| if (!is_int($i)) { | ||
| throw new \LogicException(); | ||
| } | ||
| } | ||
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.